[PATCH V5 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
qup_wait_writeready waits only on a output fifo empty event. Change the same function to accept the event and data length to wait as parameters. This way the same function can be used for timeouts in other places as well. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 67 +++- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index fdcbdab..81ed120 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -98,6 +98,9 @@ #define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_READ_LIMIT 256 +#define SET_BIT0x1 +#define RESET_BIT 0x0 +#define ONE_BYTE 0x1 struct qup_i2c_dev { struct device *dev; @@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) +/** + * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path + * @qup: The qup_i2c_dev device + * @op: The bit/event to wait on + * @val: value of the bit to wait on, 0 or 1 + * @len: The length the bytes to be transferred + */ +static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, + int len) { unsigned long timeout; u32 opflags; u32 status; + u32 shift = __ffs(op); - timeout = jiffies + HZ; + len *= qup->one_byte_t; + /* timeout after a wait of twice the max time */ + timeout = jiffies + len * 4; for (;;) { opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); - if (!(opflags & QUP_OUT_NOT_EMPTY) && - !(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (((opflags & op) >> shift) == val) { + if (op == QUP_OUT_NOT_EMPTY) { + if (!(status & I2C_STATUS_BUS_ACTIVE)) + return 0; + } else { + return 0; + } + } if (time_after(jiffies, timeout)) return -ETIMEDOUT; - usleep_range(qup->one_byte_t, qup->one_byte_t * 2); + usleep_range(len, len * 2); } } @@ -261,13 +280,13 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } -static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr = msg->addr << 1; u32 qup_tag; - u32 opflags; int idx; u32 val; + int ret = 0; if (qup->pos == 0) { val = QUP_TAG_START | addr; @@ -279,9 +298,10 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) while (qup->pos < msg->len) { /* Check that there's space in the FIFO for our pair */ - opflags = readl(qup->base + QUP_OPERATIONAL); - if (opflags & QUP_OUT_FULL) - break; + ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT, +4 * ONE_BYTE); + if (ret) + return ret; if (qup->pos == msg->len - 1) qup_tag = QUP_TAG_STOP; @@ -300,6 +320,8 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) qup->pos++; idx++; } + + return ret; } static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) @@ -325,7 +347,9 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) if (ret) goto err; - qup_i2c_issue_write(qup, msg); + ret = qup_i2c_issue_write(qup, msg); + if (ret) + goto err; ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) @@ -347,7 +371,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) } while (qup->pos < msg->len); /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_writeready(qup); + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); err: disable_irq(qup->irq); @@ -384,18 +408,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) } -static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int qup_i2c_
[PATCH V5 0/6] i2c: qup: Add support for v2 tags and bam dma
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports and is required for adding bam dma capabilities. V2 tags supports transfer of more than 256 bytes in a single i2c transaction. Also adding bam dma support facilitates transferring each i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some of the clients. Tested this series on apq8074 dragon board eeprom client on i2c bus1 [V5] Addressed few more comments from Ivan T. Ivanov. Squashed patch 2 and 3 as no point in having only few lines of common code between v1 and v2 tags for increased complexity. Couple of non functional review comments fixes in patch 3, 4. Added a change in patch 4 to have proper transfer completion in a corner case. patch 5, 6 unchanged. [V4] Added a patch to factor out some common code. Removed support for freq > 400KHZ as per comments. Addressed comments from Ivan T. Ivanov to keep the code for V2 support in a separate path. Changed the authorship of V2 tags support patch. [V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and block mode in Patch 2. Also addressed further code comments. http://comments.gmane.org/gmane.linux.drivers.i2c/22497 [V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version Sricharan R (6): i2c: qup: Change qup_wait_writeready function to use for all timeouts i2c: qup: Add V2 tags support i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit i2c: qup: Add bam dma capabilities dts: msm8974: Add blsp2_bam dma node dts: msm8974: Add dma channels for blsp2_i2c1 node arch/arm/boot/dts/qcom-msm8974.dtsi | 14 +- drivers/i2c/busses/i2c-qup.c| 931 ++-- 2 files changed, 896 insertions(+), 49 deletions(-) -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V5 3/6] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
The definition of i2c_msg says that "If this is the last message in a group, it is followed by a STOP. Otherwise it is followed by the next @i2c_msg transaction segment, beginning with a (repeated) START" So the expectation is that there is no 'STOP' bit inbetween individual i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way to inform that there should not be a 'STOP' at the end of transaction. The only way to implement this is to coalesce all the i2c_msg in i2c_msgs in to one transaction and transfer them. Adding the support for the same. This is required for some clients like touchscreen which keeps incrementing counts across individual transfers and 'STOP' bit inbetween resets the counter, which is not required. This patch adds the support in non-dma mode. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 34 ++ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 715d4d7..f9009d6 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -112,6 +112,7 @@ #define SET_BIT0x1 #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) struct qup_i2c_block { int count; @@ -147,6 +148,12 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + /* To check if this is the last msg */ + boolis_last; + + /* To configure when bus is in run state */ + int config_run; + struct completion xfer; }; @@ -269,7 +276,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, status = readl(qup->base + QUP_I2C_STATUS); if (((opflags & op) >> shift) == val) { - if (op == QUP_OUT_NOT_EMPTY) { + if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { if (!(status & I2C_STATUS_BUS_ACTIVE)) return 0; } else { @@ -290,6 +297,8 @@ static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, /* Number of entries to shift out, including the tags */ int total = msg->len + qup->blk.tx_tag_len; + total |= qup->config_run; + if (total < qup->out_fifo_sz) { /* FIFO mode */ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); @@ -443,7 +452,7 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, } /* Send _STOP commands for the last block */ - if (qup->blk.pos == (qup->blk.count - 1)) { + if ((qup->blk.pos == (qup->blk.count - 1)) && qup->is_last) { if (msg->flags & I2C_M_RD) tags[len++] = QUP_TAG_V2_DATARD_STOP; else @@ -581,7 +590,6 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) /* Wait for the outstanding data in the fifo to drain */ ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); - err: disable_irq(qup->irq); qup->msg = NULL; @@ -608,18 +616,20 @@ static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len) int tx_len = qup->blk.tx_tag_len; len += qup->blk.rx_tag_len; + len |= qup->config_run; + tx_len |= qup->config_run; if (len < qup->in_fifo_sz) { /* FIFO mode */ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(len, qup->base + QUP_MX_READ_CNT); writel(tx_len, qup->base + QUP_MX_WRITE_CNT); + writel(len, qup->base + QUP_MX_READ_CNT); } else { /* BLOCK mode (transfer data on chunks) */ writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(len, qup->base + QUP_MX_INPUT_CNT); writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT); + writel(len, qup->base + QUP_MX_INPUT_CNT); } } @@ -866,6 +876,12 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, goto out; } + qup->is_last = (idx == (num - 1)); + if (idx) + qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN; + else + qup->config_run = 0; + reinit_completion(&qup->xfer); if (msgs[idx].flags & I2C_M_RD) @@ -873,13 +889,13 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, else ret = qup
[PATCH V5 5/6] dts: msm8974: Add blsp2_bam dma node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 753bdfd..7786408 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -1,6 +1,6 @@ /dts-v1/; -#include +#include #include #include "skeleton.dtsi" @@ -345,6 +345,16 @@ interrupt-controller; #interrupt-cells = <4>; }; + + blsp2_dma: dma-controller@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x19000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; }; smd { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V5 2/6] i2c: qup: Add V2 tags support
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 415 --- 1 file changed, 386 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 81ed120..715d4d7 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -42,6 +42,7 @@ #define QUP_IN_FIFO_BASE 0x218 #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -69,6 +70,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -79,6 +82,7 @@ #define QUP_PACK_ENBIT(15) #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) @@ -91,6 +95,13 @@ #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +113,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +struct qup_i2c_block { + int count; + int pos; + int tx_tag_len; + int rx_tag_len; + int data_len; + u8 tags[6]; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -117,6 +137,7 @@ struct qup_i2c_dev { int in_blk_sz; unsigned long one_byte_t; + struct qup_i2c_blockblk; struct i2c_msg *msg; /* Current posion in user message buffer */ @@ -263,6 +284,24 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, } } +static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, + struct i2c_msg *msg) +{ + /* Number of entries to shift out, including the tags */ + int total = msg->len + qup->blk.tx_tag_len; + + if (total < qup->out_fifo_sz) { + /* FIFO mode */ + writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); + writel(total, qup->base + QUP_MX_WRITE_CNT); + } else { + /* BLOCK mode (transfer data on chunks) */ + writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, + qup->base + QUP_IO_MODE); + writel(total, qup->base + QUP_MX_OUTPUT_CNT); + } +} + static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) { /* Number of entries to shift out, including the start */ @@ -324,9 +363,189 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) return ret; } -static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup, +struct i2c_msg *msg) +{ + memset(&qup->blk, 0, sizeof(qup->blk)); + + qup->blk.data_len = msg->len; + qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT; + + /* 4 bytes for first block and 2 writes for rest */ + qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2; + + /* There are 2 tag bytes that are read in to fifo for every block */ + if (msg->flags & I2C_M_RD) + qup->blk.rx_tag_len = qup->blk.count * 2; +} + +static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf, +int dlen, u8 *dbuf) +{ + u32 val = 0, idx = 0, pos = 0, i = 0, t; + int len = tlen + dlen; + u8 *buf = tbuf; + int ret = 0; + + while (len > 0) { + ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, +RESET
[PATCH V5 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 7786408..bd1be53 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -328,6 +328,8 @@ clock-names = "core", "iface"; #address-cells = <1>; #size-cells = <0>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "tx", "rx"; }; spmi_bus: spmi@fc4cf000 { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V5 4/6] i2c: qup: Add bam dma capabilities
QUP cores can be attached to a BAM module, which acts as a dma engine for the QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data is written to the output FIFO and the BAM producer pipe received data is read from the input FIFO. With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a 'stop' which is not possible otherwise. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 447 ++- 1 file changed, 439 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index f9009d6..4ca1669 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -14,8 +14,12 @@ * */ +#include #include #include +#include +#include +#include #include #include #include @@ -24,6 +28,7 @@ #include #include #include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -33,6 +38,7 @@ #define QUP_OPERATIONAL0x018 #define QUP_ERROR_FLAGS0x01c #define QUP_ERROR_FLAGS_EN 0x020 +#define QUP_OPERATIONAL_MASK 0x028 #define QUP_HW_VERSION 0x030 #define QUP_MX_OUTPUT_CNT 0x100 #define QUP_OUT_FIFO_BASE 0x110 @@ -52,6 +58,7 @@ #define QUP_STATE_VALIDBIT(2) #define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) #define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_I2C_STATUS_RESET 0xfc @@ -77,7 +84,10 @@ /* Packing/Unpacking words in FIFOs, and IO modes */ #define QUP_OUTPUT_BLK_MODE(1 << 10) +#define QUP_OUTPUT_BAM_MODE(3 << 10) #define QUP_INPUT_BLK_MODE (1 << 12) +#define QUP_INPUT_BAM_MODE (3 << 12) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) #define QUP_UNPACK_EN BIT(14) #define QUP_PACK_ENBIT(15) @@ -94,6 +104,8 @@ #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +#define QUP_BAM_INPUT_EOT 0x93 +#define QUP_BAM_FLUSH_STOP 0x96 /* QUP v2 tags */ #define QUP_TAG_V2_START 0x81 @@ -114,6 +126,12 @@ #define ONE_BYTE 0x1 #define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +/* Max timeout in ms for 32k bytes */ +#define TOUT_MAX 300 + struct qup_i2c_block { int count; int pos; @@ -123,6 +141,17 @@ struct qup_i2c_block { u8 tags[6]; }; +struct qup_i2c_tag { + u8 *start; + dma_addr_t addr; +}; + +struct qup_i2c_bam { + struct qup_i2c_tag tag; + struct dma_chan *dma; + struct scatterlist *sg; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -154,6 +183,13 @@ struct qup_i2c_dev { /* To configure when bus is in run state */ int config_run; + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct qup_i2c_tag start_tag; + struct qup_i2c_bam brx; + struct qup_i2c_bam btx; + struct completion xfer; }; @@ -230,6 +266,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); } +static void qup_i2c_flush(struct qup_i2c_dev *qup) +{ + u32 val = readl(qup->base + QUP_STATE); + + val |= QUP_I2C_FLUSH; + writel(val, qup->base + QUP_STATE); +} + static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) { return qup_i2c_poll_state_mask(qup, 0, 0); @@ -437,12 +481,14 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup) } static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, - struct i2c_msg *msg) + struct i2c_msg *msg, int is_dma) { u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); int len = 0; int data_len; + int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last); + if (qup->blk.pos == 0) { tags[len++] = QUP_TAG_V2_START; tags[len++] = addr & 0xff; @@ -452,7 +498,7 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, } /* Send _STOP commands for the last block */ - if ((qup->blk.pos == (qup->blk.count - 1)) && qup->is_last) { + if (last) { if (msg->flags & I2C_M_RD) tags[len++] = QUP_TAG_V2_DATARD_STOP; else @@ -472,6 +518,11 @@ static int qup_i2c_s
[PATCH 0/5] iommu/msm: Add DT adaptation and generic bindings support
The msm_iommu.c driver currently works based on platform data. A single master device can be connected to more than one iommu and multiple contexts in each of the iommu. This association between master and iommus was represented from platform data using parent/child devices. The master drivers were responsible for attaching all of the iommus/context to a domain. Now the platform data support is removed and DT support is added. The master/iommus are added through generic iommu bindings. This is essentially rework of the patch posted earlier by Rob Clark . This series folds the changes in to the existing driver with the addition of generic bindings. http://www.spinics.net/lists/linux-arm-msm/msg10077.html This series is based on the IOMMU probe deferral series from Laurent Pinchart https://lkml.org/lkml/2015/5/14/786 Tested this series on ifc6410 board. Sricharan R (5): iommu/msm: Add DT adaptation iommu/msm: Move the contents from msm_iommu_dev.c to msm_iommu.c iommu/msm: Add support for generic master bindings iommu/msm: Set cacheability attributes without tex remap iommu/msm: Remove driver BROKEN .../devicetree/bindings/iommu/msm,iommu-v0.txt | 59 +++ drivers/iommu/Kconfig | 1 - drivers/iommu/Makefile | 2 +- drivers/iommu/msm_iommu.c | 508 ++--- drivers/iommu/msm_iommu.h | 73 ++- drivers/iommu/msm_iommu_dev.c | 392 drivers/iommu/msm_iommu_hw-8xxx.h | 10 +- 7 files changed, 432 insertions(+), 613 deletions(-) create mode 100644 Documentation/devicetree/bindings/iommu/msm,iommu-v0.txt delete mode 100644 drivers/iommu/msm_iommu_dev.c -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/5] iommu/msm: Add support for generic master bindings
This adds the xlate callback which gets invoked during device registration from DT. The master devices gets added through this. Also adding the iommu_of_setup callback here. Signed-off-by: Sricharan R --- drivers/iommu/msm_iommu.c | 51 +-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 1210152..1d95d7c 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -702,6 +703,44 @@ static void print_ctx_regs(void __iomem *base, int ctx) GET_PRRR(base, ctx), GET_NMRR(base, ctx)); } +static void insert_iommu_master(struct device *dev, + struct msm_iommu_dev *iommu, + struct of_phandle_args *spec) +{ + struct msm_iommu_ctx_dev *master; + int sid; + + master = kzalloc(sizeof(*master), GFP_KERNEL); + master->of_node = dev->of_node; + list_add(&master->list, &iommu->ctx_list); + + for (sid = 0; sid < spec->args_count; sid++) + master->mids[sid] = spec->args[sid]; + + master->num_mids = spec->args_count; +} + +static int qcom_iommu_of_xlate(struct device *dev, + struct of_phandle_args *spec) +{ + struct msm_iommu_dev *iommu; + unsigned long flags; + + spin_lock_irqsave(&msm_iommu_lock, flags); + list_for_each_entry(iommu, &qcom_iommu_devices, dev_node) { + if (iommu->dev->of_node == spec->np) + break; + } + + if (!iommu || (iommu->dev->of_node != spec->np)) + return -ENODEV; + + insert_iommu_master(dev, iommu, spec); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + + return 0; +} + irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) { struct msm_iommu_dev *iommu = dev_id; @@ -737,7 +776,7 @@ fail: return 0; } -static const struct iommu_ops msm_iommu_ops = { +static struct iommu_ops msm_iommu_ops = { .capable = msm_iommu_capable, .domain_alloc = msm_iommu_domain_alloc, .domain_free = msm_iommu_domain_free, @@ -748,6 +787,7 @@ static const struct iommu_ops msm_iommu_ops = { .map_sg = default_iommu_map_sg, .iova_to_phys = msm_iommu_iova_to_phys, .pgsize_bitmap = MSM_IOMMU_PGSIZES, + .of_xlate = qcom_iommu_of_xlate, }; static int msm_iommu_probe(struct platform_device *pdev) @@ -832,6 +872,7 @@ static int msm_iommu_probe(struct platform_device *pdev) } list_add(&iommu->dev_node, &qcom_iommu_devices); + of_iommu_set_ops(pdev->dev.of_node, &msm_iommu_ops); pr_info("device mapped at %p, irq %d with %d ctx banks\n", iommu->base, iommu->irq, iommu->ncb); @@ -916,7 +957,13 @@ static int __init msm_iommu_init(void) return 0; } -subsys_initcall(msm_iommu_init); +static int __init msm_iommu_of_setup(struct device_node *np) +{ + msm_iommu_init(); + return 0; +} + +IOMMU_OF_DECLARE(msm_iommu_of, "qcom,iommu-v0", msm_iommu_of_setup); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Stepan Moskovchenko "); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/5] iommu/msm: Move the contents from msm_iommu_dev.c to msm_iommu.c
There are only two functions left in msm_iommu_dev.c. Move it to msm_iommu.c and delete the file. Signed-off-by: Sricharan R --- drivers/iommu/Makefile| 2 +- drivers/iommu/msm_iommu.c | 163 + drivers/iommu/msm_iommu_dev.c | 204 -- 3 files changed, 164 insertions(+), 205 deletions(-) delete mode 100644 drivers/iommu/msm_iommu_dev.c diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index c6dcc51..83ee0bf 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o -obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o +obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm-smmu.o diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 6024d71..1210152 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,47 @@ static void __disable_clocks(struct msm_iommu_dev *iommu) clk_disable_unprepare(iommu->pclk); } +static void msm_iommu_reset(void __iomem *base, int ncb) +{ + int ctx; + + SET_RPUE(base, 0); + SET_RPUEIE(base, 0); + SET_ESRRESTORE(base, 0); + SET_TBE(base, 0); + SET_CR(base, 0); + SET_SPDMBE(base, 0); + SET_TESTBUSCR(base, 0); + SET_TLBRSW(base, 0); + SET_GLOBAL_TLBIALL(base, 0); + SET_RPU_ACR(base, 0); + SET_TLBLKCRWE(base, 1); + + for (ctx = 0; ctx < ncb; ctx++) { + SET_BPRCOSH(base, ctx, 0); + SET_BPRCISH(base, ctx, 0); + SET_BPRCNSH(base, ctx, 0); + SET_BPSHCFG(base, ctx, 0); + SET_BPMTCFG(base, ctx, 0); + SET_ACTLR(base, ctx, 0); + SET_SCTLR(base, ctx, 0); + SET_FSRRESTORE(base, ctx, 0); + SET_TTBR0(base, ctx, 0); + SET_TTBR1(base, ctx, 0); + SET_TTBCR(base, ctx, 0); + SET_BFBCR(base, ctx, 0); + SET_PAR(base, ctx, 0); + SET_FAR(base, ctx, 0); + SET_CTX_TLBIALL(base, ctx, 0); + SET_TLBFLPTER(base, ctx, 0); + SET_TLBSLPTER(base, ctx, 0); + SET_TLBLKCR(base, ctx, 0); + SET_PRRR(base, ctx, 0); + SET_NMRR(base, ctx, 0); + SET_CONTEXTIDR(base, ctx, 0); + } +} + static int __flush_iotlb(struct iommu_domain *domain) { struct msm_priv *priv = to_msm_priv(domain); @@ -708,6 +750,127 @@ static const struct iommu_ops msm_iommu_ops = { .pgsize_bitmap = MSM_IOMMU_PGSIZES, }; +static int msm_iommu_probe(struct platform_device *pdev) +{ + struct resource *r; + struct msm_iommu_dev *iommu; + int ret, par, val; + + iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL); + if (!iommu) { + ret = -ENODEV; + goto fail; + } + + iommu->dev = &pdev->dev; + INIT_LIST_HEAD(&iommu->ctx_list); + + iommu->pclk = devm_clk_get(iommu->dev, "smmu_pclk"); + if (IS_ERR(iommu->pclk)) { + dev_err(iommu->dev, "could not get smmu_pclk\n"); + ret = PTR_ERR(iommu->pclk); + goto fail; + } + + iommu->clk = devm_clk_get(iommu->dev, "iommu_clk"); + if (IS_ERR(iommu->clk)) { + dev_err(iommu->dev, "could not get iommu_clk\n"); + ret = PTR_ERR(iommu->clk); + iommu->pclk = NULL; + goto fail; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iommu->base = devm_ioremap_resource(iommu->dev, r); + if (IS_ERR(iommu->base)) { + dev_err(iommu->dev, "could not get iommu base\n"); + ret = PTR_ERR(iommu->base); + goto fail; + } + + iommu->irq = platform_get_irq(pdev, 0); + if (iommu->irq < 0) { + dev_err(iommu->dev, "could not get iommu irq\n"); + ret = -ENODEV; + goto fail; + } + + ret = of_property_read_u32(iommu->dev->of_node, "ncb", &val); + if (ret) { + dev_err(iommu->dev, "could not get ncb\n"); + goto fail; + } + iommu->ncb = val; + + __enable_clocks(iommu); + + msm_iommu_reset(iommu->base, iommu->ncb); + SET_M(iommu->base, 0, 1); + SET_PAR(iommu->base, 0, 0); + SET_V2PCFG(iomm
[PATCH 5/5] iommu/msm: Remove driver BROKEN
Now that the driver is DT adapted, bus_set_iommu gets called only when on compatible matching. So the driver should not break multiplatform builds now. So remove the BROKEN config. Signed-off-by: Sricharan R --- drivers/iommu/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index f1fb1d3..147de52 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -64,7 +64,6 @@ config MSM_IOMMU bool "MSM IOMMU Support" depends on ARM depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST - depends on BROKEN select IOMMU_API help Support for the IOMMUs found on certain Qualcomm SOCs. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] iommu/msm: Set cacheability attributes without tex remap
The cacheablity attributes are set when IOMMU_CACHE property is true. So cachebility is set as either noncached (normal) or cached (normal WBWA) directly and avoid setting using tex remap. Signed-off-by: Sricharan R --- drivers/iommu/msm_iommu.c | 66 +++ drivers/iommu/msm_iommu_hw-8xxx.h | 10 ++ 2 files changed, 8 insertions(+), 68 deletions(-) diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 1d95d7c..d554ffa 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -41,14 +41,9 @@ __asm__ __volatile__ ( \ " mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \ : "=r" (reg)) -#define RCP15_PRRR(reg)MRC(reg, p15, 0, c10, c2, 0) -#define RCP15_NMRR(reg)MRC(reg, p15, 0, c10, c2, 1) - /* bitmap of the page sizes currently supported */ #define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M) -static int msm_iommu_tex_class[4]; - DEFINE_SPINLOCK(msm_iommu_lock); static LIST_HEAD(qcom_iommu_devices); @@ -122,8 +117,6 @@ static void msm_iommu_reset(void __iomem *base, int ncb) SET_TLBFLPTER(base, ctx, 0); SET_TLBSLPTER(base, ctx, 0); SET_TLBLKCR(base, ctx, 0); - SET_PRRR(base, ctx, 0); - SET_NMRR(base, ctx, 0); SET_CONTEXTIDR(base, ctx, 0); } } @@ -232,13 +225,10 @@ static void __reset_context(void __iomem *base, int ctx) SET_TLBFLPTER(base, ctx, 0); SET_TLBSLPTER(base, ctx, 0); SET_TLBLKCR(base, ctx, 0); - SET_PRRR(base, ctx, 0); - SET_NMRR(base, ctx, 0); } static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) { - unsigned int prrr, nmrr; __reset_context(base, ctx); /* Set up HTW mode */ @@ -268,15 +258,6 @@ static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) SET_RCOSH(base, ctx, 1); SET_RCNSH(base, ctx, 1); - /* Turn on TEX Remap */ - SET_TRE(base, ctx, 1); - - /* Set TEX remap attributes */ - RCP15_PRRR(prrr); - RCP15_NMRR(nmrr); - SET_PRRR(base, ctx, prrr); - SET_NMRR(base, ctx, nmrr); - /* Turn on BFB prefetch */ SET_BFBDFE(base, ctx, 1); @@ -452,7 +433,11 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va, spin_lock_irqsave(&msm_iommu_lock, flags); sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0; - tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK]; + + tex = TEX_0; + + if (prot & IOMMU_CACHE) + tex |= BUFFERABLE | CACHEABLE; if (tex < 0 || tex > NUM_TEX_CLASS - 1) { ret = -EINVAL; @@ -699,8 +684,6 @@ static void print_ctx_regs(void __iomem *base, int ctx) GET_TTBR0(base, ctx), GET_TTBR1(base, ctx)); pr_err("SCTLR = %08xACTLR = %08x\n", GET_SCTLR(base, ctx), GET_ACTLR(base, ctx)); - pr_err("PRRR = %08xNMRR = %08x\n", - GET_PRRR(base, ctx), GET_NMRR(base, ctx)); } static void insert_iommu_master(struct device *dev, @@ -912,47 +895,8 @@ static void __exit msm_iommu_driver_exit(void) subsys_initcall(msm_iommu_driver_init); module_exit(msm_iommu_driver_exit); -static int __init get_tex_class(int icp, int ocp, int mt, int nos) -{ - int i = 0; - unsigned int prrr = 0; - unsigned int nmrr = 0; - int c_icp, c_ocp, c_mt, c_nos; - - RCP15_PRRR(prrr); - RCP15_NMRR(nmrr); - - for (i = 0; i < NUM_TEX_CLASS; i++) { - c_nos = PRRR_NOS(prrr, i); - c_mt = PRRR_MT(prrr, i); - c_icp = NMRR_ICP(nmrr, i); - c_ocp = NMRR_OCP(nmrr, i); - - if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos) - return i; - } - - return -ENODEV; -} - -static void __init setup_iommu_tex_classes(void) -{ - msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] = - get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1); - - msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] = - get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1); - - msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] = - get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1); - - msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] = - get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1); -} - static int __init msm_iommu_init(void) { - setup_iommu_tex_classes(); bus_set_iommu(&platform_bus_type, &msm_iommu_ops); return 0; } diff --git a/drivers/iommu/msm_iommu_hw-8xxx.h b/drivers/iommu/msm_iommu_hw-8xxx.h ind
[PATCH 1/5] iommu/msm: Add DT adaptation
The driver currently works based on platform data. Remove this and add support for DT. A single master can have multiple ports connected to more than one iommu. master | | | | | IOMMU0 IOMMU1 | | ctx0 ctx1ctx0 ctx1 This association of master and iommus/contexts were previously represented by platform data parent/child device details. The client drivers were responsible for programming all of the iommus/contexts for the device. Now while adapting to generic DT bindings we maintain the list of iommus, contexts that each master domain is connected to and program all of them on attach/detach. Signed-off-by: Sricharan R --- .../devicetree/bindings/iommu/msm,iommu-v0.txt | 59 drivers/iommu/msm_iommu.c | 252 drivers/iommu/msm_iommu.h | 73 ++--- drivers/iommu/msm_iommu_dev.c | 320 + 4 files changed, 289 insertions(+), 415 deletions(-) create mode 100644 Documentation/devicetree/bindings/iommu/msm,iommu-v0.txt diff --git a/Documentation/devicetree/bindings/iommu/msm,iommu-v0.txt b/Documentation/devicetree/bindings/iommu/msm,iommu-v0.txt new file mode 100644 index 000..21bfbfc --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/msm,iommu-v0.txt @@ -0,0 +1,59 @@ +* QCOM IOMMU + +The QCOM IOMMU is an implementation compatible with the ARM VMSA short +descriptor page tables. It provides address translation for bus masters outside +of the CPU, each connected to the IOMMU through a port called micro-TLB. + +Required Properties: + + - compatible: Must contain "qcom,iommu-v0". + - reg: Base address and size of the IOMMU registers. + - interrupts: Specifiers for the MMU fault interrupts. For instances that +support secure mode two interrupts must be specified, for non-secure and +secure mode, in that order. For instances that don't support secure mode a +single interrupt must be specified. + - #iommu-cells: This is the total number of stream ids that a master would + use during transactions which will be specified as a list + as a part of iommus property below. + - ncb: The total number of context banks in the IOMMU. + - clocks : List of clocks to be used during SMMU register access. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entry in clock-names + (see below). + + - clock-names: List of clock names corresponding to the clocks specified in + the "clocks" property (above). See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for more info. + +Each bus master connected to an IOMMU must reference the IOMMU in its device +node with the following property: + + - iommus: A reference to the IOMMU in multiple cells. The first cell is a + phandle to the IOMMU and the second cell is the list of the + stream ids used by the device. + +Example: mdp iommu and its bus master + +mdp_port0: qcom,iommu@750 { + compatible = "qcom,iommu-v0"; + #iommu-cells = <2>; + clock-names = + "smmu_pclk", + "iommu_clk"; + clocks = + <&mmcc SMMU_AHB_CLK>, + <&mmcc MDP_AXI_CLK>; + reg = <0x0750 0x10>; + interrupts = + , + ; + ncb = <2>; + }; + + mdp: qcom,mdp@510 { + compatible = "qcom,mdp"; + ... + iommus = <&mdp_port0 0 2>; + }; diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 15a2063..6024d71 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -48,6 +48,7 @@ __asm__ __volatile__ ( \ static int msm_iommu_tex_class[4]; DEFINE_SPINLOCK(msm_iommu_lock); +static LIST_HEAD(qcom_iommu_devices); struct msm_priv { unsigned long *pgtable; @@ -60,35 +61,37 @@ static struct msm_priv *to_msm_priv(struct iommu_domain *dom) return container_of(dom, struct msm_priv, domain); } -static int __enable_clocks(struct msm_iommu_drvdata *drvdata) +static int __enable_clocks(struct msm_iommu_
[RFC PATCH 4/4] iommu/arm-smmu: Add support for specifying regulators
From: Mitchel Humpherys This adds the support to turn on the regulators required for SMMUs. It is turned on during the SMMU probe and remains 'on' till the device exists. Signed-off-by: Sricharan R --- .../devicetree/bindings/iommu/arm,smmu.txt | 3 ++ drivers/iommu/arm-smmu.c | 48 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index c2cf4fe..433d778 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -60,6 +60,9 @@ conditions. Documentation/devicetree/bindings/clock/clock-bindings.txt for more info. +- vdd-supply: Phandle of the regulator that should be powered on during + SMMU register access. + Example: smmu { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 80d56f0a..c92de50 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -326,6 +326,8 @@ struct arm_smmu_device { int num_clocks; struct clk **clocks; + + struct regulator*regulator; }; struct arm_smmu_cfg { @@ -559,6 +561,22 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx) clear_bit(idx, map); } +static int arm_smmu_enable_regulators(struct arm_smmu_device *smmu) +{ + if (!smmu->regulator) + return 0; + + return regulator_enable(smmu->regulator); +} + +static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu) +{ + if (!smmu->regulator) + return 0; + + return regulator_disable(smmu->regulator); +} + /* Wait for any pending TLB invalidations to complete */ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu) { @@ -1583,6 +1601,20 @@ static int arm_smmu_id_size_to_bits(int size) } } +static int arm_smmu_init_regulators(struct arm_smmu_device *smmu) +{ + struct device *dev = smmu->dev; + + if (!of_get_property(dev->of_node, "vdd-supply", NULL)) + return 0; + + smmu->regulator = devm_regulator_get(dev, "vdd"); + if (IS_ERR(smmu->regulator)) + return PTR_ERR(smmu->regulator); + + return 0; +} + static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) { const char *cname; @@ -1841,11 +1873,21 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) smmu->irqs[i] = irq; } + err = arm_smmu_init_regulators(smmu); + if (err) + goto out_put_masters; + err = arm_smmu_init_clocks(smmu); if (err) goto out_put_masters; - arm_smmu_enable_clocks(smmu); + err = arm_smmu_enable_regulators(smmu); + if (err) + goto out_put_masters; + + err = arm_smmu_enable_clocks(smmu); + if (err) + goto out_disable_regulators; err = arm_smmu_device_cfg_probe(smmu); if (err) @@ -1908,6 +1950,9 @@ out_free_irqs: out_disable_clocks: arm_smmu_disable_clocks(smmu); +out_disable_regulators: + arm_smmu_disable_regulators(smmu); + out_put_masters: for (node = rb_first(&smmu->masters); node; node = rb_next(node)) { struct arm_smmu_master *master @@ -1953,6 +1998,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) /* Turn the thing off */ writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); arm_smmu_disable_clocks(smmu); + arm_smmu_disable_regulators(smmu); return 0; } -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 2/4] iommu/arm-smmu: Add xlate callback for initializing master devices from dt
This adds of_xlate callback to arm-smmu driver. xlate callback is called during device registration from DT for those master devices attached to iommus using generic iommu bindings. Signed-off-by: Sricharan R --- drivers/iommu/arm-smmu.c | 36 1 file changed, 36 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8c4eb43..2cf65ab 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -321,6 +321,7 @@ struct arm_smmu_device { unsigned int*irqs; struct list_headlist; + struct device_node *node; struct rb_root masters; }; @@ -1434,6 +1435,38 @@ out_unlock: return ret; } +static int arm_smmu_of_xlate(struct device *dev, +struct of_phandle_args *spec) +{ + struct arm_smmu_device *smmu; + struct arm_smmu_master *master; + int streamid; + + spin_lock(&arm_smmu_devices_lock); + list_for_each_entry(smmu, &arm_smmu_devices, list) { + if (smmu->node == spec->np) + break; + } + spin_unlock(&arm_smmu_devices_lock); + + if (!smmu || (smmu->node != spec->np)) + return -ENODEV; + + spec->np = dev->of_node; + + master = find_smmu_master(smmu, spec->np); + if (!master) { + if (register_smmu_master(smmu, smmu->dev, spec)) + return -ENODEV; + } else { + streamid = master->cfg.num_streamids; + master->cfg.streamids[streamid] = spec->args[0]; + master->cfg.num_streamids++; + } + + return 0; +} + static struct iommu_ops arm_smmu_ops = { .capable= arm_smmu_capable, .domain_init= arm_smmu_domain_init, @@ -1449,6 +1482,7 @@ static struct iommu_ops arm_smmu_ops = { .domain_get_attr= arm_smmu_domain_get_attr, .domain_set_attr= arm_smmu_domain_set_attr, .pgsize_bitmap = -1UL, /* Restricted during device attach */ + .of_xlate = arm_smmu_of_xlate, }; static void arm_smmu_device_reset(struct arm_smmu_device *smmu) @@ -1782,6 +1816,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } } + smmu->node = dev->of_node; + INIT_LIST_HEAD(&smmu->list); spin_lock(&arm_smmu_devices_lock); list_add(&smmu->list, &arm_smmu_devices); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 1/4] iommu/arm-smmu: Init driver using IOMMU_OF_DECLARE
This patch uses IOMMU_OF_DECLARE to register the driver and the iommu_ops. So when master devices of the iommu are registered, of_xlate callback can be used to add the master configurations to the smmu driver. Signed-off-by: Sricharan R --- drivers/iommu/arm-smmu.c | 36 +++- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index fc13dd5..8c4eb43 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include @@ -254,6 +256,8 @@ #define FSYNR0_WNR (1 << 4) static int force_stage; +static bool init_done; + module_param_named(force_stage, force_stage, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(force_stage, "Force SMMU mappings to be installed at a particular stage of translation. A value of '1' or '2' forces the corresponding stage. All other values are ignored (i.e. no stage is forced). Note that selecting a specific stage will disable support for nested translation."); @@ -1848,20 +1852,8 @@ static struct platform_driver arm_smmu_driver = { static int __init arm_smmu_init(void) { - struct device_node *np; int ret; - /* -* Play nice with systems that don't have an ARM SMMU by checking that -* an ARM SMMU exists in the system before proceeding with the driver -* and IOMMU bus operation registration. -*/ - np = of_find_matching_node(NULL, arm_smmu_of_match); - if (!np) - return 0; - - of_node_put(np); - ret = platform_driver_register(&arm_smmu_driver); if (ret) return ret; @@ -1880,15 +1872,33 @@ static int __init arm_smmu_init(void) bus_set_iommu(&pci_bus_type, &arm_smmu_ops); #endif + init_done = true; + return 0; } +static int __init arm_smmu_of_setup(struct device_node *np) +{ + + if (!init_done) + arm_smmu_init(); + + of_iommu_set_ops(np, &arm_smmu_ops); + + return 0; +} + +IOMMU_OF_DECLARE(arm_smmu_v1, "arm,smmu-v1", arm_smmu_of_setup); +IOMMU_OF_DECLARE(arm_smmu_v2, "arm,smmu-v2", arm_smmu_of_setup); +IOMMU_OF_DECLARE(arm_smmu_400, "arm,mmu-400", arm_smmu_of_setup); +IOMMU_OF_DECLARE(arm_smmu_401, "arm,mmu-401", arm_smmu_of_setup); +IOMMU_OF_DECLARE(arm_smmu_500, "arm,mmu-500", arm_smmu_of_setup); + static void __exit arm_smmu_exit(void) { return platform_driver_unregister(&arm_smmu_driver); } -subsys_initcall(arm_smmu_init); module_exit(arm_smmu_exit); MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 3/4] iommu/arm-smmu: Add support for specifying clocks
From: Mitchel Humpherys On some platforms with tight power constraints it is polite to only leave your clocks on for as long as you absolutely need them. Currently we assume that all clocks necessary for SMMU register access are always on. Add some optional device tree properties to specify any clocks that are necessary for SMMU register access and turn them on and off as needed. If no clocks are specified in the device tree things continue to work the way they always have: we assume all necessary clocks are always turned on. The clocks are turned 'on' during the SMMU device probe and remains 'on' till the device exists. Signed-off-by: Mitchel Humpherys Signed-off-by: Sricharan R --- .../devicetree/bindings/iommu/arm,smmu.txt | 11 +++ drivers/iommu/arm-smmu.c | 86 +- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 0676050..c2cf4fe 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -49,6 +49,17 @@ conditions. aliases of secure registers have to be used during SMMU configuration. +- clocks : List of clocks to be used during SMMU register access. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entery in clock-names + (see below). + +- clock-names : List of clock names corresponding to the clocks specified in + the "clocks" property (above). See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for more info. + Example: smmu { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 2cf65ab..80d56f0a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -323,6 +323,9 @@ struct arm_smmu_device { struct list_headlist; struct device_node *node; struct rb_root masters; + + int num_clocks; + struct clk **clocks; }; struct arm_smmu_cfg { @@ -365,6 +368,31 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { 0, NULL}, }; +static int arm_smmu_enable_clocks(struct arm_smmu_device *smmu) +{ + int i, ret = 0; + + for (i = 0; i < smmu->num_clocks; ++i) { + ret = clk_prepare_enable(smmu->clocks[i]); + if (ret) { + dev_err(smmu->dev, "Couldn't enable clock #%d\n", i); + while (i--) + clk_disable_unprepare(smmu->clocks[i]); + break; + } + } + + return ret; +} + +static void arm_smmu_disable_clocks(struct arm_smmu_device *smmu) +{ + int i; + + for (i = 0; i < smmu->num_clocks; ++i) + clk_disable_unprepare(smmu->clocks[i]); +} + static void parse_driver_options(struct arm_smmu_device *smmu) { int i = 0; @@ -1555,6 +1583,47 @@ static int arm_smmu_id_size_to_bits(int size) } } +static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) +{ + const char *cname; + struct property *prop; + int i; + struct device *dev = smmu->dev; + + smmu->num_clocks = + of_property_count_strings(dev->of_node, "clock-names"); + + if (smmu->num_clocks < 1) + return 0; + + smmu->clocks = devm_kzalloc( + dev, sizeof(*smmu->clocks) * smmu->num_clocks, + GFP_KERNEL); + + if (!smmu->clocks) { + dev_err(dev, + "Failed to allocate memory for clocks\n"); + return -ENODEV; + } + + i = 0; + of_property_for_each_string(dev->of_node, "clock-names", + prop, cname) { + struct clk *c = devm_clk_get(dev, cname); + + if (IS_ERR(c)) { + dev_err(dev, "Couldn't get clock: %s", + cname); + return -ENODEV; + } + + smmu->clocks[i] = c; + + ++i; + } + return 0; +} + static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) { unsigned long size; @@ -1772,9 +1841,15 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) smmu->irqs[i] = irq; } + err = arm_smmu_init_clocks(smmu); + if (err) + goto out_put_masters; + + arm_smmu_enab
[RFC PATCH 0/4] iommu/arm-smmu: Add support for adding masters/clocks using generic bindings
This series adds support for xlate callback to add master devices configs using generic bindings and clocks/regulators required to access smmu. OF_IOMMU_DECLARE is used to register and probe the smmu controller devices before the masters are added in of_platform_populate. Here, we are registering only the smmu driver and iommu_ops. The smmu device registration is not done in OF_IOMMU_DECLARE to avoid early smmu probe, because the clocks if any required for the controller are not yet ready. So the idea here is to get the right direction in adding this support. Mitchel Humpherys (2): iommu/arm-smmu: add support for specifying clocks iommu/arm-smmu: Add support for specifying regulators Sricharan R (2): iommu/arm-smmu: Init driver using IOMMU_OF_DECLARE iommu/arm-smmu: Add xlate callback for initializing master devices from dt .../devicetree/bindings/iommu/arm,smmu.txt | 14 ++ drivers/iommu/arm-smmu.c | 210 +++-- 2 files changed, 208 insertions(+), 16 deletions(-) -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC] drivers: dma-coherent: Change order of allocation to PAGE_SIZE
dma_alloc_from_coherent uses get_order(size) which makes carve-out allocations not aligned on order boundaries to fail even though they are page aligned. So wanted to know why is it required to have the size aligned on order boundary. Changing it to get_order(PAGE_SIZE) makes the non aligned carve-out allocations to go through. Signed-off-by: Sricharan R --- drivers/base/dma-coherent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 55b8398..72bdc6f 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -156,7 +156,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, dma_addr_t *dma_handle, void **ret) { struct dma_coherent_mem *mem; - int order = get_order(size); + int order = get_order(PAGE_SIZE); unsigned long flags; int pageno; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V4 6/7] dts: msm8974: Add blsp2_bam dma node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 37b47b5..f138202 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -1,6 +1,6 @@ /dts-v1/; -#include +#include #include #include "skeleton.dtsi" @@ -301,5 +301,15 @@ interrupt-controller; #interrupt-cells = <4>; }; + + blsp2_dma: dma-controller@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x19000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; }; }; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V4 2/7] qup: i2c: factor out common code for reuse
The qup_i2c_write/read_one functions can be split to have the common initialization code and function to loop around the data bytes separately. This way the initialization code can be reused while adding v2 tags functionality. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 147 +-- 1 file changed, 87 insertions(+), 60 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 81ed120..131dc28 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -324,53 +324,72 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) return ret; } -static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, +struct i2c_msg *msg) { unsigned long left; - int ret; - - qup->msg = msg; - qup->pos = 0; + int ret = 0; - enable_irq(qup->irq); + left = wait_for_completion_timeout(&qup->xfer, HZ); + if (!left) { + writel(1, qup->base + QUP_SW_RESET); + ret = -ETIMEDOUT; + } - qup_i2c_set_write_mode(qup, msg); + if (qup->bus_err || qup->qup_err) { + if (qup->bus_err & QUP_I2C_NACK_FLAG) { + dev_err(qup->dev, "NACK from %x\n", msg->addr); + ret = -EIO; + } + } - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto err; + return ret; +} - writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); +static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) +{ + int ret = 0; do { ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); if (ret) - goto err; + return ret; ret = qup_i2c_issue_write(qup, msg); if (ret) - goto err; + return ret; ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) - goto err; - - left = wait_for_completion_timeout(&qup->xfer, HZ); - if (!left) { - writel(1, qup->base + QUP_SW_RESET); - ret = -ETIMEDOUT; - goto err; - } + return ret; - if (qup->bus_err || qup->qup_err) { - if (qup->bus_err & QUP_I2C_NACK_FLAG) - dev_err(qup->dev, "NACK from %x\n", msg->addr); - ret = -EIO; - goto err; - } + ret = qup_i2c_wait_for_complete(qup, msg); + if (ret) + return ret; } while (qup->pos < msg->len); - /* Wait for the outstanding data in the fifo to drain */ + return ret; +} + +static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +{ + int ret; + + qup->msg = msg; + qup->pos = 0; + enable_irq(qup->irq); + qup_i2c_set_write_mode(qup, msg); + + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + goto err; + + writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); + + ret = qup_i2c_write_one(qup, msg); + if (ret) + goto err; + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); err: @@ -436,51 +455,59 @@ static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - unsigned long left; - int ret; + int ret = 0; - qup->msg = msg; - qup->pos = 0; + /* +* The QUP block will issue a NACK and STOP on the bus when reaching +* the end of the read, the length of the read is specified as one byte +* which limits the possible read to 256 (QUP_READ_LIMIT) bytes. +*/ + if (msg->len > QUP_READ_LIMIT) { + dev_err(qup->dev, "HW not capable of reads over %d bytes\n", + QUP_READ_LIMIT); + return -EINVAL; + } - enable_irq(qup->irq); + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + if (ret) + return ret; - qup_i2c_set_read_mode(qup, msg->len); + qup_i2c_issue_read(qup, msg); ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) - goto err; + return ret; - writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); + do { + ret = qup_i2c_wait_for_c
[PATCH V4 3/7] i2c: qup: Add V2 tags support
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 330 ++- 1 file changed, 323 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 131dc28..a4e20d9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -43,6 +43,8 @@ #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 + /* QUP States and reset values */ #define QUP_RESET_STATE0 #define QUP_RUN_STATE 1 @@ -69,6 +71,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -79,6 +83,7 @@ #define QUP_PACK_ENBIT(15) #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) @@ -91,6 +96,13 @@ #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +114,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +struct qup_i2c_block { + int count; + int pos; + int tx_tag_len; + int rx_tag_len; + int data_len; + u8 tags[6]; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -117,6 +138,7 @@ struct qup_i2c_dev { int in_blk_sz; unsigned long one_byte_t; + struct qup_i2c_blockblk; struct i2c_msg *msg; /* Current posion in user message buffer */ @@ -126,6 +148,14 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + int use_v2_tags; + + int (*qup_i2c_write_one)(struct qup_i2c_dev *qup, +struct i2c_msg *msg); + + int (*qup_i2c_read_one)(struct qup_i2c_dev *qup, + struct i2c_msg *msg); + struct completion xfer; }; @@ -266,7 +296,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) { /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + int total = msg->len + qup->blk.tx_tag_len; if (total < qup->out_fifo_sz) { /* FIFO mode */ @@ -324,6 +354,134 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) return ret; } +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup, +struct i2c_msg *msg) +{ + memset(&qup->blk, 0, sizeof(qup->blk)); + + if (!qup->use_v2_tags) { + if (!(msg->flags & I2C_M_RD)) + qup->blk.tx_tag_len = 1; + return; + } + + qup->blk.data_len = msg->len; + qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT; + + /* 4 bytes for first block and 2 writes for rest */ + qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2; + + /* There are 2 tag bytes that are read in to fifo for every block */ + if (msg->flags & I2C_M_RD) + qup->blk.rx_tag_len = qup->blk.count * 2; +} + +static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf, +int dlen, u8 *dbuf) +{ + u32 val = 0, idx = 0, pos = 0, i = 0, t; + int len = tlen + dlen; + u8 *buf = tbuf; + int ret = 0; + + while (len > 0) { + ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, +RESET_BIT, 4 * ONE_BYTE); +
[PATCH V4 5/7] i2c: qup: Add bam dma capabilities
QUP cores can be attached to a BAM module, which acts as a dma engine for the QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data is written to the output FIFO and the BAM producer pipe received data is read from the input FIFO. With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a 'stop' which is not possible otherwise. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 431 +-- 1 file changed, 415 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index c0757d9..810b021 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -24,6 +24,11 @@ #include #include #include +#include +#include +#include +#include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -33,6 +38,7 @@ #define QUP_OPERATIONAL0x018 #define QUP_ERROR_FLAGS0x01c #define QUP_ERROR_FLAGS_EN 0x020 +#define QUP_OPERATIONAL_MASK 0x028 #define QUP_HW_VERSION 0x030 #define QUP_MX_OUTPUT_CNT 0x100 #define QUP_OUT_FIFO_BASE 0x110 @@ -53,6 +59,7 @@ #define QUP_STATE_VALIDBIT(2) #define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) #define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_I2C_STATUS_RESET 0xfc @@ -78,7 +85,10 @@ /* Packing/Unpacking words in FIFOs, and IO modes */ #define QUP_OUTPUT_BLK_MODE(1 << 10) +#define QUP_OUTPUT_BAM_MODE(3 << 10) #define QUP_INPUT_BLK_MODE (1 << 12) +#define QUP_INPUT_BAM_MODE (3 << 12) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) #define QUP_UNPACK_EN BIT(14) #define QUP_PACK_ENBIT(15) @@ -95,6 +105,8 @@ #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +#define QUP_BAM_INPUT_EOT 0x93 +#define QUP_BAM_FLUSH_STOP 0x96 /* QUP v2 tags */ #define QUP_TAG_V2_START 0x81 @@ -115,6 +127,12 @@ #define ONE_BYTE 0x1 #define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +/* Max timeout in ms for 32k bytes */ +#define TOUT_MAX 300 + struct qup_i2c_block { int count; int pos; @@ -125,6 +143,23 @@ struct qup_i2c_block { int config_run; }; +struct qup_i2c_tag { + u8 *start; + dma_addr_t addr; +}; + +struct qup_i2c_bam_rx { + struct qup_i2c_tag scratch_tag; + struct dma_chan *dma_rx; + struct scatterlist *sg_rx; +}; + +struct qup_i2c_bam_tx { + struct qup_i2c_tag footer_tag; + struct dma_chan *dma_tx; + struct scatterlist *sg_tx; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -154,14 +189,20 @@ struct qup_i2c_dev { int (*qup_i2c_write_one)(struct qup_i2c_dev *qup, struct i2c_msg *msg); + int (*qup_i2c_read_one)(struct qup_i2c_dev *qup, + struct i2c_msg *msg); + /* Current i2c_msg in i2c_msgs */ int cmsg; /* total num of i2c_msgs */ int num; - int (*qup_i2c_read_one)(struct qup_i2c_dev *qup, - struct i2c_msg *msg); - + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct qup_i2c_tag start_tag; + struct qup_i2c_bam_rx brx; + struct qup_i2c_bam_tx btx; struct completion xfer; }; @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); } +static void qup_i2c_flush(struct qup_i2c_dev *qup) +{ + u32 val = readl(qup->base + QUP_STATE); + + val |= QUP_I2C_FLUSH; + writel(val, qup->base + QUP_STATE); +} + static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) { return qup_i2c_poll_state_mask(qup, 0, 0); @@ -437,12 +486,15 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup) } static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup, - struct i2c_msg *msg) + struct i2c_msg *msg, int is_dma) { u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); int len = 0; int data_len; + int last = (qup->blk.pos == (qup->blk.count - 1)) && + (qup->cmsg == (qup->num - 1)); + if (qup->blk.pos == 0) {
[PATCH V4 0/7] i2c: qup: Add support for v2 tags and bam dma
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports and is required for adding bam dma capabilities. V2 tags supports transfer of more than 256 bytes in a single i2c transaction. Also adding bam dma support facilitates transferring each i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some of the clients. Tested this series on apq8074 dragon board eeprom client on i2c bus1 [V4] Added a patch to factor out some common code. Removed support for freq > 400KHZ as per comments. Addressed comments from Ivan T. Ivanov to keep the code for V2 support in a separate path. Changed the authorship of V2 tags support patch. [V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and block mode in Patch 2. Also addressed further code comments. http://comments.gmane.org/gmane.linux.drivers.i2c/22497 [V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version Sricharan R (7): i2c: qup: Change qup_wait_writeready function to use for all timeouts qup: i2c: factor out common code for reuse i2c: qup: Add V2 tags support i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit i2c: qup: Add bam dma capabilities dts: msm8974: Add blsp2_bam dma node dts: msm8974: Add dma channels for blsp2_i2c1 node arch/arm/boot/dts/qcom-msm8974.dtsi | 14 +- drivers/i2c/busses/i2c-qup.c| 943 +--- 2 files changed, 880 insertions(+), 77 deletions(-) -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V4 7/7] dts: msm8974: Add dma channels for blsp2_i2c1 node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index f138202..17dcda3 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -284,6 +284,8 @@ clock-names = "core", "iface"; #address-cells = <1>; #size-cells = <0>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "tx", "rx"; }; spmi_bus: spmi@fc4cf000 { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
The definition of i2c_msg says that "If this is the last message in a group, it is followed by a STOP. Otherwise it is followed by the next @i2c_msg transaction segment, beginning with a (repeated) START" So the expectation is that there is no 'STOP' bit inbetween individual i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way to inform that there should not be a 'STOP' at the end of transaction. The only way to implement this is to coalesce all the i2c_msg in i2c_msgs in to one transaction and transfer them. Adding the support for the same. This is required for some clients like touchscreen which keeps incrementing counts across individual transfers and 'STOP' bit inbetween resets the counter, which is not required. This patch adds the support in non-dma mode. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 40 ++-- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index a4e20d9..c0757d9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -113,6 +113,7 @@ #define SET_BIT0x1 #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) struct qup_i2c_block { int count; @@ -121,6 +122,7 @@ struct qup_i2c_block { int rx_tag_len; int data_len; u8 tags[6]; + int config_run; }; struct qup_i2c_dev { @@ -152,6 +154,10 @@ struct qup_i2c_dev { int (*qup_i2c_write_one)(struct qup_i2c_dev *qup, struct i2c_msg *msg); + /* Current i2c_msg in i2c_msgs */ + int cmsg; + /* total num of i2c_msgs */ + int num; int (*qup_i2c_read_one)(struct qup_i2c_dev *qup, struct i2c_msg *msg); @@ -278,7 +284,8 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, status = readl(qup->base + QUP_I2C_STATUS); if (((opflags & op) >> shift) == val) { - if (op == QUP_OUT_NOT_EMPTY) { + if ((op == QUP_OUT_NOT_EMPTY) && + (qup->cmsg == (qup->num - 1))) { if (!(status & I2C_STATUS_BUS_ACTIVE)) return 0; } else { @@ -301,12 +308,14 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) if (total < qup->out_fifo_sz) { /* FIFO mode */ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_WRITE_CNT); + writel(total | qup->blk.config_run, + qup->base + QUP_MX_WRITE_CNT); } else { /* BLOCK mode (transfer data on chunks) */ writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_OUTPUT_CNT); + writel(total | qup->blk.config_run, + qup->base + QUP_MX_OUTPUT_CNT); } } @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup, /* There are 2 tag bytes that are read in to fifo for every block */ if (msg->flags & I2C_M_RD) qup->blk.rx_tag_len = qup->blk.count * 2; + + if (qup->cmsg) + qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN; } static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf, @@ -440,7 +452,8 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup, } /* Send _STOP commands for the last block */ - if (qup->blk.pos == (qup->blk.count - 1)) { + if (qup->blk.pos == (qup->blk.count - 1) + && (qup->cmsg == (qup->num - 1))) { if (msg->flags & I2C_M_RD) tags[len++] = QUP_TAG_V2_DATARD_STOP; else @@ -571,7 +584,6 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) goto err; ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); - err: disable_irq(qup->irq); qup->msg = NULL; @@ -584,18 +596,19 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len) int tx_len = qup->blk.tx_tag_len; len += qup->blk.rx_tag_len; + tx_len |= qup->blk.config_run; if (len < qup->in_fifo_sz) { /* FIFO mode */ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(len, qup->base + QUP_MX_READ
[PATCH V4 1/7] i2c: qup: Change qup_wait_writeready function to use for all timeouts
qup_wait_writeready waits only on a output fifo empty event. Change the same function to accept the event and data length to wait as parameters. This way the same function can be used for timeouts in otherplaces as well. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 67 +++- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index fdcbdab..81ed120 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -98,6 +98,9 @@ #define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_READ_LIMIT 256 +#define SET_BIT0x1 +#define RESET_BIT 0x0 +#define ONE_BYTE 0x1 struct qup_i2c_dev { struct device *dev; @@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) +/** + * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path + * @qup: The qup_i2c_dev device + * @op: The bit/event to wait on + * @val: value of the bit to wait on, 0 or 1 + * @len: The length the bytes to be transferred + */ +static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, + int len) { unsigned long timeout; u32 opflags; u32 status; + u32 shift = __ffs(op); - timeout = jiffies + HZ; + len *= qup->one_byte_t; + /* timeout after a wait of twice the max time */ + timeout = jiffies + len * 4; for (;;) { opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); - if (!(opflags & QUP_OUT_NOT_EMPTY) && - !(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (((opflags & op) >> shift) == val) { + if (op == QUP_OUT_NOT_EMPTY) { + if (!(status & I2C_STATUS_BUS_ACTIVE)) + return 0; + } else { + return 0; + } + } if (time_after(jiffies, timeout)) return -ETIMEDOUT; - usleep_range(qup->one_byte_t, qup->one_byte_t * 2); + usleep_range(len, len * 2); } } @@ -261,13 +280,13 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } -static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr = msg->addr << 1; u32 qup_tag; - u32 opflags; int idx; u32 val; + int ret = 0; if (qup->pos == 0) { val = QUP_TAG_START | addr; @@ -279,9 +298,10 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) while (qup->pos < msg->len) { /* Check that there's space in the FIFO for our pair */ - opflags = readl(qup->base + QUP_OPERATIONAL); - if (opflags & QUP_OUT_FULL) - break; + ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT, +4 * ONE_BYTE); + if (ret) + return ret; if (qup->pos == msg->len - 1) qup_tag = QUP_TAG_STOP; @@ -300,6 +320,8 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) qup->pos++; idx++; } + + return ret; } static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) @@ -325,7 +347,9 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) if (ret) goto err; - qup_i2c_issue_write(qup, msg); + ret = qup_i2c_issue_write(qup, msg); + if (ret) + goto err; ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) @@ -347,7 +371,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) } while (qup->pos < msg->len); /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_writeready(qup); + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); err: disable_irq(qup->irq); @@ -384,18 +408,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) } -static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int qup_i2c_
[PATCH] iommu/arm-smmu: Fix bug in ARM_SMMU_FEAT_TRANS_OPS condition check
Patch 'fix ARM_SMMU_FEAT_TRANS_OPS condition' changed the check for ARM_SMMU_FEAT_TRANS_OPS to be based on presence of stage1 check, but used (id & ID0_ATOSNS) instead of !(id & ID0_ATOSNS). Fix it here. Signed-off-by: Sricharan R --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 09091e9..fbf4af6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1866,7 +1866,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } - if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) { + if ((id & ID0_S1TS) && ((smmu->version == 1) || !(id & ID0_ATOSNS))) { smmu->features |= ARM_SMMU_FEAT_TRANS_OPS; dev_notice(smmu->dev, "\taddress translation ops\n"); } -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V3 2/6] i2c: qup: Add V2 tags support
Hi Ivan, On 04/16/2015 02:06 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Wed, 2015-04-15 at 20:14 +0530, Sricharan R wrote: +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) Could you explain what is this for? This is a new feature in the V2 version of the controller, to support multiple i2c sub transfers without having a 'stop' bit in-between. Without this the i2c controller inserts a 'stop' on the bus when the WR/RD count registers reaches zero and are configured for the next transfer. So setting this bit when the controller is in 'RUN' state, avoids sending the 'stop' during RUN state. I can add this comment in the patch. And how v2 of this patch was worked if you introduce this bit now? Bit is also not used by downstream driver, AFICS? The one of the reason for this and the bam support patches in this series was to support multiple transfers of i2c_msgs without a 'stop' inbetween them. So without that the driver sends a 'stop' between each sub-transfer. Are you saying that there is bug in the hardware? Please, could you point me to codeaurora driver, which is using this bit? The controller was not supporting this 'no-stop' feature by default and not sure whether to call it a 'bug' or 'missing feature', which it supports now anyway. Regarding the internal driver, it was trying to coalesce the writes (if they are to same address) by configuring the WR_CNT register to the sum of msg->len of the consecutive sub-transfers. This is no more needed with this 'feature'. -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg, + int run) And 'run' stands for? 'run' just says whether the controller is in 'RUN' or 'RESET' state. I can change it to is_run_st to make it clear. { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) { + total = msg->len + qup->tx_tag_len; + if (run) + total |= QUP_I2C_MX_CONFIG_DURING_RUN; What? This means, if the controller is in 'RUN' state, for reconfiguring the RD/WR counts this bit has to be set to avoid 'stop' bits. I don't buy it, sorry. Problem with v1 of the tags is that controller can not read more than 256 bytes without automatically generate STOP at the end, because transfer length specified with QUP_TAG_REC tag is 8 bits wide. There is no limitation for writes with v1 tags, because controller is explicitly instructed when to send out STOP. correct till this. For v2 of the tags, writes behaves more or less the same, and the good news are that there is new read tag QUP_TAG_V2_DATARD, which did't generate STOP when specified amount of data is read, still up to 256 bytes in chunk. Read transfers with size more than 256 could be formed in following way: V2_START | Slave Address | V2_DATARD | countx | ... | V2_DATARD_STOP | county. The above is true for a single subtransfer for reading/writing more than > 256 bytes. But for doing WRITE, READ kind of sub transfers once the first sub transfer (write) is over, and while re-configuring the _COUNT registers for the next transfers, 'a stop' between is inserted. From controller itself or driver? controller itself. +static void qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) +{ + u32 data_len = 0, tag_len; + + tag_len = qup->blk.block_tag_len[qup->blk.block_pos]; + + if (!(msg->flags & I2C_M_RD)) + data_len = qup->blk.block_data_len[qup->blk.block_pos]; + + qup_i2c_send_data(qup, tag_len, qup->tags, data_len, msg->buf); This assumes that writes are up to 256 bytes, and tags and data blocks are completely written to FIFO buffer, right? Yes, since we send/read data in blocks (256 bytes). How deep is the FIFO? Is it guaranteed that "the whole" write or read data, including tags will fit in. Write/read fifo functions (also for V1) currently wait for the fifo full and empty flags conditions. I will say that this is true for v1, but not for v2, because the way of how FIFO is filled in v2. fifo is filled using the same 'flags' in both v1 and v2. The difference is the way tags and data are assembled in the output. But as i said, it can be improved atleast in v2 easily (can be done in v1 also, but is not something required in this patch) and i will change that in next version. +stati
Re: [PATCH V3 2/6] i2c: qup: Add V2 tags support
Hi Ivan, Sorry resending again, because wrapping seemed to be somehow wrong in my previous response. On 04/15/2015 02:19 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Wed, 2015-04-15 at 12:09 +0530, Sricharan R wrote: +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 This is fast mode, if I am not mistaken. ya, up to 1MHZ is fast and up to 3.4MHZ is HS. We use this macro to check if the desired freq is in HS range. The above comment can be changed though to make it clear. My point was that this is neither high nor max speed. I see that QUP specs defines up to 1MHZ as fast+ speed. + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +119,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) Could you explain what is this for? This is a new feature in the V2 version of the controller, to support multiple i2c sub transfers without having a 'stop' bit in-between. Without this the i2c controller inserts a 'stop' on the bus when the WR/RD count registers reaches zero and are configured for the next transfer. So setting this bit when the controller is in 'RUN' state, avoids sending the 'stop' during RUN state. I can add this comment in the patch. And how v2 of this patch was worked if you introduce this bit now? Bit is also not used by downstream driver, AFICS? The one of the reason for this and the bam support patches in this series was to support multiple transfers of i2c_msgs without a 'stop' inbetween them. So without that the driver sends a 'stop' between each sub-transfer. The v2 of this series supported that only in bam mode and not in non-bam mode. That was a bug. I saw the difference in behavior between bam and non-bam mode while testing with a hdmi adv bridge recently. So added the support in this series. This was neede to bringup the HDMI adv bridge device. I could have added it as a new patch to make it more explicit. + +struct qup_i2c_block { + int blocks; count + u8 *block_tag_len; just tag_len, + int *block_data_len; just data_len, + int block_pos; just pos? +}; + struct qup_i2c_dev { struct device*dev; void __iomem*base; @@ -115,9 +141,17 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + struct qup_i2c_blockblk; unsigned longone_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg*msg; /* Current posion in user message buffer */ int pos; @@ -263,10 +297,19 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, } } Is this better tag related fields grouping? struct qup_i2c_tag_block { u8 tag[2]; // int tag_len; this is alway 2, or? int data_len; // this could be zero, right? }; There is a struct for qup_i2c_block which has tag and data len. Not sure what change you suggest above ? Also with V2 transfers tag len need not be 2. It can be more than that based on the data len. The point is that: I will like to see better grouping of related variables. Now they are spread all over. Would it be possible to also take care for tx_tag_len, rx_tag_len, tags, tags_pos. For this and the above, i will change the groupings and split this patch in to couple of smaller ones. -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg, + int run) And 'run' stands for? 'run' just says whether the controller is in 'RUN' or 'RESET' state. I can change it to is_run_st to make it clear. { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) { + total = msg->len + qup->tx_tag_len; + if (run) + total |= QUP_I2C_MX_CONFIG_DURING_RUN; What? This means, if the controller is in 'RUN' state, for reconfiguring the RD/WR counts this bit has to be set to avoid 'stop' bits. I don't buy it, sorry. Problem with v1 of the tags is that controller can not read more than 256 bytes without automatically generate STOP at the end, because transfer length specified with QUP
Re: [PATCH V3 2/6] i2c: qup: Add V2 tags support
Hi Ivan, On 04/15/2015 02:19 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Wed, 2015-04-15 at 12:09 +0530, Sricharan R wrote: +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 This is fast mode, if I am not mistaken. ya, up to 1MHZ is fast and up to 3.4MHZ is HS. We use this macro to check if the desired freq is in HS range. The above comment can be changed though to make it clear. My point was that this is neither high nor max speed. I see that QUP specs defines up to 1MHZ as fast+ speed. + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +119,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) Could you explain what is this for? This is a new feature in the V2 version of the controller, to support multiple i2c sub transfers without having a 'stop' bit in-between. Without this the i2c controller inserts a 'stop' on the bus when the WR/RD count registers reaches zero and are configured for the next transfer. So setting this bit when the controller is in 'RUN' state, avoids sending the 'stop' during RUN state. I can add this comment in the patch. And how v2 of this patch was worked if you introduce this bit now? Bit is also not used by downstream driver, AFICS? The one of the reason for this and the bam support patches in this series was to support multiple transfers of i2c_msgs without a 'stop' inbetween them. So without that the driver sends a 'stop' between each sub-transfer. The v2 of this series supported that only in bam mode and not in non-bam mode. That was a bug. I saw the difference in behavior between bam and non-bam mode while testing with a hdmi adv bridge recently. So added the support in this series. This was neede to bringup the HDMI adv bridge device. I could have added it as a new patch to make it more explicit. + +struct qup_i2c_block { + int blocks; count + u8 *block_tag_len; just tag_len, + int *block_data_len; just data_len, + int block_pos; just pos? +}; + struct qup_i2c_dev { struct device*dev; void __iomem*base; @@ -115,9 +141,17 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + struct qup_i2c_blockblk; unsigned longone_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg*msg; /* Current posion in user message buffer */ int pos; @@ -263,10 +297,19 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, } } Is this better tag related fields grouping? struct qup_i2c_tag_block { u8 tag[2]; // int tag_len; this is alway 2, or? int data_len; // this could be zero, right? }; There is a struct for qup_i2c_block which has tag and data len. Not sure what change you suggest above ? Also with V2 transfers tag len need not be 2. It can be more than that based on the data len. The point is that: I will like to see better grouping of related variables. Now they are spread all over. Would it be possible to also take care for tx_tag_len, rx_tag_len, tags, tags_pos. For this and the above, i will change the groupings and split this patch in to couple of smaller ones. -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg, + int run) And 'run' stands for? 'run' just says whether the controller is in 'RUN' or 'RESET' state. I can change it to is_run_st to make it clear. { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) { + total = msg->len + qup->tx_tag_len; + if (run) + total |= QUP_I2C_MX_CONFIG_DURING_RUN; What? This means, if the controller is in 'RUN' state, for reconfiguring the RD/WR counts this bit has to be set to avoid 'stop' bits. I don't buy it, sorry. Problem with v1 of the tags is that controller can not read more than 256 bytes without automatically generate STOP at the end, because transfer length specified with QUP_TAG_REC tag is 8 bits wide. There is no limitation for writes with v1 tags, because c
Re: [PATCH V3 2/6] i2c: qup: Add V2 tags support
Hi Ivan, On 04/14/2015 08:46 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Sat, 2015-04-11 at 12:39 +0530, Sricharan R wrote: From: Andy Gross QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. But the read and write messages size QUP_READ_LIMIT? The READ_LIMIT is not true with the V2 tags. The controller can read/write multiple of 256 bytes sub-transfers to make transactions greater than > 256. Infact, i will have to remove the check for the READ_LIMIT in case of V2. I will add that. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- [V3] Addressed comments from Andy Gross to coalesce each i2c_msg in i2c_msgs as a single transfer. Added macros to i2c_wait_ready function. drivers/i2c/busses/i2c-qup.c | 393 +-- 1 file changed, 337 insertions(+), 56 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 9ccf3e8..16a8f69 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -24,6 +24,7 @@ #include #include #include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -42,6 +43,7 @@ #define QUP_IN_FIFO_BASE 0x218 #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -69,6 +71,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -80,17 +84,30 @@ #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 + #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) #define QUP_INPUT_BLOCK_SIZE(x)(((x) >> 5) & 0x03) #define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07) -/* QUP tags */ +/* QUP V1 tags */ #define QUP_TAG_START (1 << 8) #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_HS 0xff +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 This is fast mode, if I am not mistaken. ya, up to 1MHZ is fast and up to 3.4MHZ is HS. We use this macro to check if the desired freq is in HS range. The above comment can be changed though to make it clear. + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +119,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) Could you explain what is this for? This is a new feature in the V2 version of the controller, to support multiple i2c sub transfers without having a 'stop' bit in-between. Without this the i2c controller inserts a 'stop' on the bus when the WR/RD count registers reaches zero and are configured for the next transfer. So setting this bit when the controller is in 'RUN' state, avoids sending the 'stop' during RUN state. I can add this comment in the patch. + +struct qup_i2c_block { + int blocks; + u8 *block_tag_len; + int *block_data_len; + int block_pos; +}; + struct qup_i2c_dev { struct device*dev; void __iomem*base; @@ -115,9 +141,17 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + struct qup_i2c_blockblk; unsigned longone_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg*msg; /* Current posion in user message buffer */ int pos; @@ -263,10 +297,19 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, } } Is this better tag related fields grouping? st
Re: [PATCH V3 5/6] dts: msm8974: Add blsp2_bam dma node
Hi, On 04/12/2015 03:42 AM, Sergei Shtylyov wrote: Hello. On 04/11/2015 10:09 AM, Sricharan R wrote: Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index e265ec1..2c26151 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi [...] @@ -247,5 +247,15 @@ #address-cells = <1>; #size-cells = <0>; }; + +blsp2_dma: dma@f9944000 { The ePAPR standard says that the node name should be "dma-controller", not just "dma". Ok, will correct this. Regards, Sricharan -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V3 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
The definition of i2c_msg says that "If this is the last message in a group, it is followed by a STOP. Otherwise it is followed by the next @i2c_msg transaction segment, beginning with a (repeated) START" So the expectation is that there is no 'STOP' bit inbetween individual i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way to inform that there should not be a 'STOP' at the end of transaction. The only way to implement this is to coalesce all the i2c_msg in i2c_msgs in to one transaction and transfer them. Adding the support for the same. This is required for some clients like touchscreen which keeps incrementing counts across individual transfers and 'STOP' bit inbetween resets the counter, which is not required. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 200 ++- 1 file changed, 122 insertions(+), 78 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4463ff8..1b71043 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -890,76 +890,94 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup) return 0; } -static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, int num) { struct dma_async_tx_descriptor *txd, *rxd = NULL; int ret = 0; dma_cookie_t cookie_rx, cookie_tx; - u32 rx_nents = 0, tx_nents = 0, len = 0; - /* QUP I2C read/write limit for single command is 256bytes max*/ - int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; - int rem = msg->len % QUP_READ_LIMIT; - int tlen, i = 0, tx_len = 0; - - if (msg->flags & I2C_M_RD) { - tx_nents = 1; - rx_nents = (blocks << 1) + 1; - sg_init_table(qup->brx.sg_rx, rx_nents); - - while (i < blocks) { - /* transfer length set to '0' implies 256 bytes */ - tlen = (i == (blocks - 1)) ? rem : 0; - len += get_start_tag(&qup->start_tag.start[len], - msg, !i, (i == (blocks - 1)), - tlen); - - qup_sg_set_buf(&qup->brx.sg_rx[i << 1], - &qup->brx.scratch_tag.start[0], - &qup->brx.scratch_tag, - 2, qup, 0, 0); - - qup_sg_set_buf(&qup->brx.sg_rx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], - NULL, tlen, qup, 1, - DMA_FROM_DEVICE); - - i++; - } - - sg_init_one(qup->btx.sg_tx, &qup->start_tag.start[0], len); - qup_sg_set_buf(qup->btx.sg_tx, &qup->start_tag.start[0], - &qup->start_tag, len, qup, 0, 0); - qup_sg_set_buf(&qup->brx.sg_rx[i << 1], - &qup->brx.scratch_tag.start[1], - &qup->brx.scratch_tag, 2, - qup, 0, 0); - } else { - qup->btx.footer_tag.start[0] = QUP_BAM_FLUSH_STOP; - qup->btx.footer_tag.start[1] = QUP_BAM_FLUSH_STOP; - - tx_nents = (blocks << 1) + 1; - sg_init_table(qup->btx.sg_tx, tx_nents); - - while (i < blocks) { - tlen = (i == (blocks - 1)) ? rem : 0; - len = get_start_tag(&qup->start_tag.start[tx_len], - msg, !i, (i == (blocks - 1)), tlen); - - qup_sg_set_buf(&qup->btx.sg_tx[i << 1], - &qup->start_tag.start[tx_len], - &qup->start_tag, - len, qup, 0, 0); - - tx_len += len; - qup_sg_set_buf(&qup->btx.sg_tx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], NULL, - tlen, qup, 1, DMA_TO_DEVICE); - i++; + u32 rx_nents = 0, tx_nents = 0, len, blocks, rem, last; + u32 cur_rx_nents, cur_tx_nents; + u32 tlen, i, tx_len, tx_buf = 0, rx_buf = 0, off = 0; + + while (num) { + blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; + rem = msg->len % QUP_READ_LIMIT; + i = 0, tx_len = 0, len = 0; + +
[PATCH V3 3/6] i2c: qup: Add bam dma capabilities
QUP cores can be attached to a BAM module, which acts as a dma engine for the QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data is written to the output FIFO and the BAM producer pipe received data is read from the input FIFO. With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a 'stop' which is not possible otherwise. Signed-off-by: Sricharan R --- [V3] Addressed comments from Andy Gross to use macros for qup_i2c_wait_ready function. drivers/i2c/busses/i2c-qup.c | 415 ++- 1 file changed, 406 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 16a8f69..4463ff8 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -25,6 +25,11 @@ #include #include #include +#include +#include +#include +#include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -34,6 +39,7 @@ #define QUP_OPERATIONAL0x018 #define QUP_ERROR_FLAGS0x01c #define QUP_ERROR_FLAGS_EN 0x020 +#define QUP_OPERATIONAL_MASK 0x028 #define QUP_HW_VERSION 0x030 #define QUP_MX_OUTPUT_CNT 0x100 #define QUP_OUT_FIFO_BASE 0x110 @@ -53,6 +59,7 @@ #define QUP_STATE_VALIDBIT(2) #define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) #define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_I2C_STATUS_RESET 0xfc @@ -78,7 +85,10 @@ /* Packing/Unpacking words in FIFOs, and IO modes */ #define QUP_OUTPUT_BLK_MODE(1 << 10) +#define QUP_OUTPUT_BAM_MODE(3 << 10) #define QUP_INPUT_BLK_MODE (1 << 12) +#define QUP_INPUT_BAM_MODE (3 << 12) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) #define QUP_UNPACK_EN BIT(14) #define QUP_PACK_ENBIT(15) @@ -105,6 +115,10 @@ #define QUP_TAG_V2_DATARD 0x85 #define QUP_TAG_V2_DATARD_STOP 0x87 +/* QUP BAM v2 tags */ +#define QUP_BAM_INPUT_EOT 0x93 +#define QUP_BAM_FLUSH_STOP 0x96 + /* frequency definitions for high speed and max speed */ #define I2C_QUP_CLK_FAST_FREQ 100 @@ -121,6 +135,12 @@ #define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +/* Max timeout in ms for 32k bytes */ +#define TOUT_MAX 300 + struct qup_i2c_block { int blocks; u8 *block_tag_len; @@ -128,6 +148,23 @@ struct qup_i2c_block { int block_pos; }; +struct qup_i2c_tag { + u8 *start; + dma_addr_t addr; +}; + +struct qup_i2c_bam_rx { + struct qup_i2c_tag scratch_tag; + struct dma_chan *dma_rx; + struct scatterlist *sg_rx; +}; + +struct qup_i2c_bam_tx { + struct qup_i2c_tag footer_tag; + struct dma_chan *dma_tx; + struct scatterlist *sg_tx; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -160,6 +197,12 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct qup_i2c_tag start_tag; + struct qup_i2c_bam_rx brx; + struct qup_i2c_bam_tx btx; struct completion xfer; }; @@ -236,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); } +static void qup_i2c_flush(struct qup_i2c_dev *qup) +{ + u32 val = readl(qup->base + QUP_STATE); + + val |= QUP_I2C_FLUSH; + writel(val, qup->base + QUP_STATE); +} + static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) { return qup_i2c_poll_state_mask(qup, 0, 0); @@ -446,7 +497,8 @@ static u32 qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf, u8 *buf = tbuf; while (len > 0) { - if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) { + if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT, + 4 * ONE_BYTE)) { dev_err(qup->dev, "timeout for fifo out full"); break; } @@ -612,7 +664,8 @@ static void qup_i2c_read_fifo_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg) for (idx = 0; qup->pos < len; idx++) { if ((idx & 1) == 0) { /* Check that FIFO have data */ - if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) { + if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, SET_BIT, +
[PATCH V3 2/6] i2c: qup: Add V2 tags support
From: Andy Gross QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- [V3] Addressed comments from Andy Gross to coalesce each i2c_msg in i2c_msgs as a single transfer. Added macros to i2c_wait_ready function. drivers/i2c/busses/i2c-qup.c | 393 +-- 1 file changed, 337 insertions(+), 56 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 9ccf3e8..16a8f69 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -24,6 +24,7 @@ #include #include #include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -42,6 +43,7 @@ #define QUP_IN_FIFO_BASE 0x218 #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -69,6 +71,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -80,17 +84,30 @@ #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 + #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) #define QUP_INPUT_BLOCK_SIZE(x)(((x) >> 5) & 0x03) #define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07) -/* QUP tags */ +/* QUP V1 tags */ #define QUP_TAG_START (1 << 8) #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_HS 0xff +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -102,6 +119,15 @@ #define RESET_BIT 0x0 #define ONE_BYTE 0x1 +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) + +struct qup_i2c_block { + int blocks; + u8 *block_tag_len; + int *block_data_len; + int block_pos; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -115,9 +141,17 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + struct qup_i2c_block blk; unsigned long one_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg *msg; /* Current posion in user message buffer */ int pos; @@ -263,10 +297,19 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, } } -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg, + int run) { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) { + total = msg->len + qup->tx_tag_len; + if (run) + total |= QUP_I2C_MX_CONFIG_DURING_RUN; + } else { + total = msg->len + 1; /* plus start tag */ + } if (total < qup->out_fifo_sz) { /* FIFO mode */ @@ -280,7 +323,7 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } -static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr = msg->
[PATCH V3 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
qup_wait_writeready waits only on a output fifo empty event. Change the same function to accept the event and data length to wait as parameters. This way the same function can be used for timeouts in otherplaces as well. Signed-off-by: Sricharan R --- [v3] Addressed comments from Andy Gross drivers/i2c/busses/i2c-qup.c | 33 ++--- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4dad23b..9ccf3e8 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -98,6 +98,9 @@ #define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_READ_LIMIT 256 +#define SET_BIT0x1 +#define RESET_BIT 0x0 +#define ONE_BYTE 0x1 struct qup_i2c_dev { struct device *dev; @@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) +/** + * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path + * @qup: The qup_i2c_dev device + * @op: The bit/event to wait on + * @val: value of the bit to wait on, 0 or 1 + * @len: The length the bytes to be transferred + */ +static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, + int len) { unsigned long timeout; u32 opflags; u32 status; + u32 shift = __ffs(op); - timeout = jiffies + HZ; + len *= qup->one_byte_t; + /* timeout after a wait of twice the max time */ + timeout = jiffies + len * 4; for (;;) { opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); - if (!(opflags & QUP_OUT_NOT_EMPTY) && - !(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (((opflags & op) >> shift) == val) { + if (op == QUP_OUT_NOT_EMPTY) { + if (!(status & I2C_STATUS_BUS_ACTIVE)) + return 0; + } else { + return 0; + } + } if (time_after(jiffies, timeout)) return -ETIMEDOUT; - usleep_range(qup->one_byte_t, qup->one_byte_t * 2); + usleep_range(len, len * 2); } } @@ -347,7 +366,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) } while (qup->pos < msg->len); /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_writeready(qup); + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); err: disable_irq(qup->irq); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V3 0/6] i2c: qup: Add support for v2 tags and bam dma
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports and is required for adding bam dma capabilities. v2 tags supports transfer of more than 256 bytes in a single i2c transaction. Also adding bam dma support facilitates transferring each i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some of the clients. This series depends on the below bam dma bug fix https://lkml.org/lkml/2015/2/20/47 Tested this series on apq8074 dragon board eeprom client on i2c bus1 [V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and block mode in Patch 2. Also addressed further code comments. [V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version Andy Gross (1): i2c: qup: Add V2 tags support Sricharan R (5): i2c: qup: Change qup_wait_writeready function to use for all timeouts i2c: qup: Add bam dma capabilities i2c: qup: Transfer every i2c_msg in i2c_msgs without stop dts: msm8974: Add blsp2_bam dma node dts: msm8974: Add dma channels for blsp2_i2c1 node arch/arm/boot/dts/qcom-msm8974.dtsi | 14 +- drivers/i2c/busses/i2c-qup.c| 877 +--- 2 files changed, 822 insertions(+), 69 deletions(-) -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V3 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 2c26151..d741856 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -246,6 +246,8 @@ clock-names = "core", "iface"; #address-cells = <1>; #size-cells = <0>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "tx", "rx"; }; blsp2_dma: dma@f9944000 { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V3 5/6] dts: msm8974: Add blsp2_bam dma node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index e265ec1..2c26151 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -1,6 +1,6 @@ /dts-v1/; -#include +#include #include #include "skeleton.dtsi" @@ -247,5 +247,15 @@ #address-cells = <1>; #size-cells = <0>; }; + + blsp2_dma: dma@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x19000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; }; }; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V2 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
Signed-off-by: Sricharan R --- [v2] Changed dma channel names as per comments. arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index c2e8711..5cb0772 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -246,6 +246,8 @@ clock-names = "core", "iface"; #address-cells = <1>; #size-cells = <0>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "tx", "rx"; }; spmi_bus: spmi@fc4cf000 { -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V2 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
The definition of i2c_msg says that "If this is the last message in a group, it is followed by a STOP. Otherwise it is followed by the next @i2c_msg transaction segment, beginning with a (repeated) START" So the expectation is that there is no 'STOP' bit inbetween individual i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way to inform that there should not be a 'STOP' at the end of transaction. The only way to implement this is to coalesce all the i2c_msg in i2c_msgs in to one transaction and transfer them. Adding the support for the same. This is required for some clients like touchscreen which keeps incrementing counts across individual transfers and 'STOP' bit inbetween resets the counter, which is not required. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 199 ++- 1 file changed, 121 insertions(+), 78 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 2fd141d..85c326f 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -830,76 +830,94 @@ void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg, sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start); } -static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, int num) { struct dma_async_tx_descriptor *txd, *rxd = NULL; int ret = 0; dma_cookie_t cookie_rx, cookie_tx; - u32 rx_nents = 0, tx_nents = 0, len = 0; - /* QUP I2C read/write limit for single command is 256bytes max*/ - int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; - int rem = msg->len % QUP_READ_LIMIT; - int tlen, i = 0, tx_len = 0; - - if (msg->flags & I2C_M_RD) { - tx_nents = 1; - rx_nents = (blocks << 1) + 1; - sg_init_table(qup->brx.sg_rx, rx_nents); - - while (i < blocks) { - /* transfer length set to '0' implies 256 bytes */ - tlen = (i == (blocks - 1)) ? rem : 0; - len += get_start_tag(&qup->start_tag.start[len], - msg, !i, (i == (blocks - 1)), - tlen); - - qup_sg_set_buf(&qup->brx.sg_rx[i << 1], - &qup->brx.scratch_tag.start[0], - &qup->brx.scratch_tag, - 2, qup, 0, 0); - - qup_sg_set_buf(&qup->brx.sg_rx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], - NULL, tlen, qup, 1, - DMA_FROM_DEVICE); - - i++; - } - - sg_init_one(qup->btx.sg_tx, &qup->start_tag.start[0], len); - qup_sg_set_buf(qup->btx.sg_tx, &qup->start_tag.start[0], - &qup->start_tag, len, qup, 0, 0); - qup_sg_set_buf(&qup->brx.sg_rx[i << 1], - &qup->brx.scratch_tag.start[1], - &qup->brx.scratch_tag, 2, - qup, 0, 0); - } else { - qup->btx.footer_tag.start[0] = QUP_BAM_FLUSH_STOP; - qup->btx.footer_tag.start[1] = QUP_BAM_FLUSH_STOP; - - tx_nents = (blocks << 1) + 1; - sg_init_table(qup->btx.sg_tx, tx_nents); - - while (i < blocks) { - tlen = (i == (blocks - 1)) ? rem : 0; - len = get_start_tag(&qup->start_tag.start[tx_len], - msg, !i, (i == (blocks - 1)), tlen); - - qup_sg_set_buf(&qup->btx.sg_tx[i << 1], - &qup->start_tag.start[tx_len], - &qup->start_tag, - len, qup, 0, 0); - - tx_len += len; - qup_sg_set_buf(&qup->btx.sg_tx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], NULL, - tlen, qup, 1, DMA_TO_DEVICE); - i++; + u32 rx_nents = 0, tx_nents = 0, len, blocks, rem, last; + u32 cur_rx_nents, cur_tx_nents; + u32 tlen, i, tx_len, tx_buf = 0, rx_buf = 0, off = 0; + + while (num) { + blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; + rem = msg->len % QUP_READ_LI
[PATCH V2 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
qup_wait_writeready waits only on a output fifo empty event. Change the same function to accept the event and data length to wait as parameters. This way the same function can be used for timeouts in otherplaces as well. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 30 +++--- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4dad23b..49c6cba 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -221,26 +221,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) +/** + * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path + * @qup: The qup_i2c_dev device + * @op: The bit/event to wait on + * @val: value of the bit to wait on, 0 or 1 + * @len: The length the bytes to be transferred + */ +static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, + int len) { unsigned long timeout; u32 opflags; u32 status; + u32 shift = __ffs(op); - timeout = jiffies + HZ; + len *= qup->one_byte_t; + /* timeout after a wait of twice the max time */ + timeout = jiffies + len * 4; for (;;) { opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); - if (!(opflags & QUP_OUT_NOT_EMPTY) && - !(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (((opflags & op) >> shift) == val) { + if (op == QUP_OUT_NOT_EMPTY) { + if (!(status & I2C_STATUS_BUS_ACTIVE)) + return 0; + } else { + return 0; + } + } if (time_after(jiffies, timeout)) return -ETIMEDOUT; - usleep_range(qup->one_byte_t, qup->one_byte_t * 2); + usleep_range(len, len * 2); } } @@ -347,7 +363,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) } while (qup->pos < msg->len); /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_writeready(qup); + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, 0, 1); err: disable_irq(qup->irq); -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V2 2/6] i2c: qup: Add V2 tags support
From: Andy Gross QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- [v2] Addressed comments from Ivan T. Ivanov drivers/i2c/busses/i2c-qup.c | 336 ++- 1 file changed, 299 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 49c6cba..8605557 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -24,6 +24,7 @@ #include #include #include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -42,6 +43,7 @@ #define QUP_IN_FIFO_BASE 0x218 #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -69,6 +71,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -80,17 +84,30 @@ #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 + #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) #define QUP_INPUT_BLOCK_SIZE(x)(((x) >> 5) & 0x03) #define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07) -/* QUP tags */ +/* QUP V1 tags */ #define QUP_TAG_START (1 << 8) #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_HS 0xff +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -99,6 +116,13 @@ #define QUP_READ_LIMIT 256 +struct qup_i2c_block { + int blocks; + u8 *block_tag_len; + int *block_data_len; + int block_pos; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -112,9 +136,17 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + struct qup_i2c_block blk; unsigned long one_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg *msg; /* Current posion in user message buffer */ int pos; @@ -262,8 +294,13 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) + total = msg->len + qup->tx_tag_len; + else + total = msg->len + 1; /* plus start tag */ if (total < qup->out_fifo_sz) { /* FIFO mode */ @@ -277,7 +314,7 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } -static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr = msg->addr << 1; u32 qup_tag; @@ -318,6 +355,134 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } +static void qup_i2c_create_tag_v2(struct qup_i2c_dev *qup, + struct i2c_msg *msg) +{ + u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); + int len = 0, prev_len = 0; + int blocks = 0; + int rem; +
[PATCH V2 5/6] dts: msm8974: Add blsp2_bam dma node
Signed-off-by: Sricharan R --- [v2] Used macros for interrupts property. arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 2d11641..c2e8711 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -1,6 +1,6 @@ /dts-v1/; -#include +#include #include #include "skeleton.dtsi" @@ -263,5 +263,15 @@ interrupt-controller; #interrupt-cells = <4>; }; + + blsp2_dma: dma@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x19000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; }; }; -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V2 3/6] i2c: qup: Add bam dma capabilities
QUP cores can be attached to a BAM module, which acts as a dma engine for the QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data is written to the output FIFO and the BAM producer pipe received data is read from the input FIFO. With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a 'stop' which is not possible otherwise. Signed-off-by: Sricharan R --- [v2] Addressed comments from Ivan T. Ivanov drivers/i2c/busses/i2c-qup.c | 371 ++- 1 file changed, 366 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 8605557..2fd141d 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -25,6 +25,11 @@ #include #include #include +#include +#include +#include +#include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -34,6 +39,7 @@ #define QUP_OPERATIONAL0x018 #define QUP_ERROR_FLAGS0x01c #define QUP_ERROR_FLAGS_EN 0x020 +#define QUP_OPERATIONAL_MASK 0x028 #define QUP_HW_VERSION 0x030 #define QUP_MX_OUTPUT_CNT 0x100 #define QUP_OUT_FIFO_BASE 0x110 @@ -53,6 +59,7 @@ #define QUP_STATE_VALIDBIT(2) #define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) #define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_I2C_STATUS_RESET 0xfc @@ -78,7 +85,10 @@ /* Packing/Unpacking words in FIFOs, and IO modes */ #define QUP_OUTPUT_BLK_MODE(1 << 10) +#define QUP_OUTPUT_BAM_MODE(3 << 10) #define QUP_INPUT_BLK_MODE (1 << 12) +#define QUP_INPUT_BAM_MODE (3 << 12) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) #define QUP_UNPACK_EN BIT(14) #define QUP_PACK_ENBIT(15) @@ -105,6 +115,10 @@ #define QUP_TAG_V2_DATARD 0x85 #define QUP_TAG_V2_DATARD_STOP 0x87 +/* QUP BAM v2 tags */ +#define QUP_BAM_INPUT_EOT 0x93 +#define QUP_BAM_FLUSH_STOP 0x96 + /* frequency definitions for high speed and max speed */ #define I2C_QUP_CLK_FAST_FREQ 100 @@ -115,6 +129,11 @@ #define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_READ_LIMIT 256 +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +/* Max timeout in ms for 32k bytes */ +#define TOUT_MAX 300 struct qup_i2c_block { int blocks; @@ -123,6 +142,23 @@ struct qup_i2c_block { int block_pos; }; +struct qup_i2c_tag { + u8 *start; + dma_addr_t addr; +}; + +struct qup_i2c_bam_rx { + struct qup_i2c_tag scratch_tag; + struct dma_chan *dma_rx; + struct scatterlist *sg_rx; +}; + +struct qup_i2c_bam_tx { + struct qup_i2c_tag footer_tag; + struct dma_chan *dma_tx; + struct scatterlist *sg_tx; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -155,6 +191,12 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct qup_i2c_tag start_tag; + struct qup_i2c_bam_rx brx; + struct qup_i2c_bam_tx btx; struct completion xfer; }; @@ -231,6 +273,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); } +static void qup_i2c_flush(struct qup_i2c_dev *qup) +{ + u32 val = readl(qup->base + QUP_STATE); + + val |= QUP_I2C_FLUSH; + writel(val, qup->base + QUP_STATE); +} + static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) { return qup_i2c_poll_state_mask(qup, 0, 0); @@ -715,12 +765,242 @@ err: return ret; } +static void qup_i2c_bam_cb(void *data) +{ + struct qup_i2c_dev *qup = data; + + complete(&qup->xfer); +} + +static int get_tag_code(struct i2c_msg *msg, int last) +{ + u8 op; + + /* always issue stop for each read block */ + if (last) { + if (msg->flags & I2C_M_RD) + op = QUP_TAG_V2_DATARD_STOP; + else + op = QUP_TAG_V2_DATAWR_STOP; + } else { + if (msg->flags & I2C_M_RD) + op = QUP_TAG_V2_DATARD; + else + op = QUP_TAG_V2_DATAWR; + } + + return op; +} + +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last, +int blen) +{ + u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); + u8 op; +
[PATCH V2 0/6] i2c: qup: Add support for v2 tags and bam dma
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports and is required for adding bam dma capabilities. v2 tags supports transfer of more than 256 bytes in a single i2c transaction. Also adding bam dma support facilitates transferring each i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some of the clients. This series depends on the below bam dma bug fix https://lkml.org/lkml/2015/2/20/47 Tested this series on apq8074 dragon board eeprom client on i2c bus1 [V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version Andy Gross (1): i2c: qup: Add V2 tags support Sricharan R (5): i2c: qup: Change qup_wait_writeready function to use for all timeouts i2c: qup: Add bam dma capabilities i2c: qup: Transfer every i2c_msg in i2c_msgs without stop dts: msm8974: Add blsp2_bam dma node dts: msm8974: Add dma channels for blsp2_i2c1 node arch/arm/boot/dts/qcom-msm8974.dtsi | 14 +- drivers/i2c/busses/i2c-qup.c| 788 +--- 2 files changed, 748 insertions(+), 54 deletions(-) -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] i2c: qup: Add V2 tags support
Hi Ivan, On 03/26/2015 01:01 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote: + if (msg->flags & I2C_M_RD) + qup->rx_tag_len = (qup->blocks << 1); here again. hmm, why not shift ? Because it makes reading code harder and because compiler is smart enough to choose appropriate instruction for underling CPU architecture. ok. + else + qup->rx_tag_len = 0; +} + +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len, + u8 *buf, int last) +{ I think that xfer is too vague in this case, prefer write or send. ok. Will change it to send. + static u32 val, idx; static? please fix. That was intentional. Using to pack tag and data in to one word across two calls. So preserving val, idx across calls. Sorry this is no go! Reorganize the code, please. Ok, will change this function. Regards, Sricharan -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/6] i2c: qup: Add bam dma capabilities
Hi Ivan, On 03/25/2015 06:40 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote: #define QUP_I2C_MASTER_GEN 0x408 +#define QUP_I2C_MASTER_CONFIG 0x408 Unused. Ok, will remove it #define QUP_READ_LIMIT 256 +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +#define TOUT_MAX 300 /* Max timeout for 32k tx/tx */ seconds, muliseconds? Ok. Will add milliseconds. struct qup_i2c_config { int tag_ver; int max_freq; }; +struct tag { Please use consistent naming convention. ok. + u8 *start; + dma_addr_t addr; +}; + struct qup_i2c_dev { struct device*dev; void __iomem*base; @@ -157,9 +181,35 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct tag start_tag; + struct tag scratch_tag; + struct tag footer_tag; + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; + struct scatterlist *sg_tx; + struct scatterlist *sg_rx; + dma_addr_tsg_tx_phys; + dma_addr_tsg_rx_phys; Maybe these could be organized in structure per direction. ok, will group it. + struct completionxfer; }; +struct i2c_bam_xfer { Unused. Right. Will remove the whole thing. Thanks. + struct qup_i2c_dev *qup; + u32 start_len; + + u32 rx_nents; + u32 tx_nents; + + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t tx_cookie; + struct dma_async_tx_descriptor *rx_desc; + dma_cookie_t rx_cookie; structure per direction. +}; + Infact should be removed. +static void bam_i2c_callback(void *data) +{ Please use consistent naming, here and bellow. ok, will change. + struct qup_i2c_dev *qup = data; + + complete(&qup->xfer); +} + +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last, + int blen) +{ + u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); + u8 op; + int len = 0; + + /* always issue stop for each read block */ + if (last) { + if (msg->flags & I2C_M_RD) + op = QUP_TAG_V2_DATARD_STOP; + else + op = QUP_TAG_V2_DATAWR_STOP; + } else { + if (msg->flags & I2C_M_RD) + op = QUP_TAG_V2_DATARD; + else + op = QUP_TAG_V2_DATAWR; + } + + if (msg->flags & I2C_M_TEN) { + len += 5; + tag[0] = QUP_TAG_V2_START; + tag[1] = addr; + tag[2] = op; + tag[3] = blen; + + if (msg->flags & I2C_M_RD && last) { + len += 2; + tag[4] = QUP_BAM_INPUT_EOT; + tag[5] = QUP_BAM_FLUSH_STOP; + } + } else { + if (first) { + tag[len++] = QUP_TAG_V2_START; + tag[len++] = addr; + } + + tag[len++] = op; + tag[len++] = blen; + + if (msg->flags & I2C_M_RD & last) { + tag[len++] = QUP_BAM_INPUT_EOT; + tag[len++] = QUP_BAM_FLUSH_STOP; + } + } + + return len; +} Maybe could be split to 2 functions? hmm, ok will split couple of small ones. -static const struct i2c_algorithm qup_i2c_algo = { +static struct i2c_algorithm qup_i2c_algo = { Why? oops. Should not have been changed. Will fix. .master_xfer= qup_i2c_xfer, .functionality= qup_i2c_func, }; @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev) u32 clk_freq = 10; const struct qup_i2c_config *config; const struct of_device_id *of_id; + int blocks; qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL); if (!qup) @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev) return qup->irq; } + if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") || + of_device_is_compatible(pdev->dev.of_node, + "qcom,i2c-qup-v2.2.1")) { Logic will be simpler if you check just for version 1 of the controller. yes. Will fix it. + qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx"); + Please use dma_request_slave_channel_reason. As Andy noted, please use just "rx", "tx" ok. will change it. + if (!qup->dma_rx) + return -EPROBE_DEFER;
Re: [PATCH 2/6] i2c: qup: Add V2 tags support
Hi Ivan, On 03/25/2015 05:54 PM, Ivan T. Ivanov wrote: Hi Sricharan, On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote: From: Andy Gross QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 342 ++- +#define I2C_QUP_CLK_MAX_FREQ 340 unused? Ok, will remove this. + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -99,6 +117,11 @@ #define QUP_READ_LIMIT 256 +struct qup_i2c_config { + int tag_ver; + int max_freq; +}; + Do you really need this one. It is referenced only during probe, but information contained in is already available by other means. Ok, agree that this can be removed and the information can be fixed for V1 version and same for the rest of the other versions. That would need to use compatible check though. struct qup_i2c_dev { struct device*dev; void __iomem*base; @@ -112,9 +135,20 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + int blocks; + u8 *block_tag_len; + int *block_data_len; Maybe these could be organized in struct? ok, will group it. +static void qup_i2c_create_tag_v2(struct qup_i2c_dev *qup, + struct i2c_msg *msg) +{ + u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD); + int len = 0, prev_len = 0; + int blocks = 0; + int rem; + int block_len = 0; + int data_len; + + qup->block_pos = 0; + qup->pos = 0; + qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT); Braces around QUP_READ_LIMIT are not needed. ok. + rem = msg->len % QUP_READ_LIMIT; + + /* 2 tag bytes for each block + 2 extra bytes for first block */ + qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL); Don't play tricks with shifts, just use multiplication. why ? + qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL); + qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL); Better use sizeof(*qup->block_data_len). ok. + + while (blocks < qup->blocks) { + /* 0 is used to specify a READ_LIMIT of 256 bytes */ + data_len = (blocks < (qup->blocks - 1)) ? 0 : rem; + + /* Send START and ADDR bytes only for the first block */ + if (!blocks) { + qup->tags[len++] = QUP_TAG_V2_START; + + if (qup->is_hs) { + qup->tags[len++] = QUP_TAG_V2_HS; + qup->tags[len++] = QUP_TAG_V2_START; Is this second QUP_TAG_V2_START intentional? Yes, for HS mode 2 start tags are required. + } + + qup->tags[len++] = addr & 0xff; + if (msg->flags & I2C_M_TEN) + qup->tags[len++] = addr >> 8; + } + + /* Send _STOP commands for the last block */ + if (blocks == (qup->blocks - 1)) { + if (msg->flags & I2C_M_RD) + qup->tags[len++] = QUP_TAG_V2_DATARD_STOP; + else + qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP; + } else { + if (msg->flags & I2C_M_RD) + qup->tags[len++] = QUP_TAG_V2_DATARD; + else + qup->tags[len++] = QUP_TAG_V2_DATAWR; + } + + qup->tags[len++] = data_len; + block_len = len - prev_len; + prev_len = len; + qup->block_tag_len[blocks] = block_len; + + if (!data_len) + qup->block_data_len[blocks] = QUP_READ_LIMIT; + else + qup->block_data_len[blocks] = data_len; + + qup->tags_pos = 0; + blocks++; + } + + qup->tx_tag_len = len; + + if (msg->flags & I2C_M_RD) + qup->rx_tag_len = (qup->blocks << 1); here again. hmm, why not shift ? + else + qup->rx_tag_len = 0;
[PATCH 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
qup_wait_writeready waits only on a output fifo empty event. Change the same function to accept the event and data length to wait as parameters. This way the same function can be used for timeouts in otherplaces as well. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 30 +++--- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4dad23b..49c6cba 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -221,26 +221,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) +/** + * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path + * @qup: The qup_i2c_dev device + * @op: The bit/event to wait on + * @val: value of the bit to wait on, 0 or 1 + * @len: The length the bytes to be transferred + */ +static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, + int len) { unsigned long timeout; u32 opflags; u32 status; + u32 shift = __ffs(op); - timeout = jiffies + HZ; + len *= qup->one_byte_t; + /* timeout after a wait of twice the max time */ + timeout = jiffies + len * 4; for (;;) { opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); - if (!(opflags & QUP_OUT_NOT_EMPTY) && - !(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (((opflags & op) >> shift) == val) { + if (op == QUP_OUT_NOT_EMPTY) { + if (!(status & I2C_STATUS_BUS_ACTIVE)) + return 0; + } else { + return 0; + } + } if (time_after(jiffies, timeout)) return -ETIMEDOUT; - usleep_range(qup->one_byte_t, qup->one_byte_t * 2); + usleep_range(len, len * 2); } } @@ -347,7 +363,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) } while (qup->pos < msg->len); /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_writeready(qup); + ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, 0, 1); err: disable_irq(qup->irq); -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index e265ec1..3f648ae 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -247,5 +247,15 @@ #address-cells = <1>; #size-cells = <0>; }; + + blsp2_dma: dma@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x19000>; + interrupts = <0 239 0>; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; }; }; -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/6] i2c: qup: Add bam dma capabilities
QUP cores can be attached to a BAM module, which acts as a dma engine for the QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data is written to the output FIFO and the BAM producer pipe received data is read from the input FIFO. With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a 'stop' which is not possible otherwise. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 365 ++- 1 file changed, 359 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index e4e223f..11ea6af 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -25,6 +25,11 @@ #include #include #include +#include +#include +#include +#include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -34,6 +39,7 @@ #define QUP_OPERATIONAL0x018 #define QUP_ERROR_FLAGS0x01c #define QUP_ERROR_FLAGS_EN 0x020 +#define QUP_OPERATIONAL_MASK 0x028 #define QUP_HW_VERSION 0x030 #define QUP_MX_OUTPUT_CNT 0x100 #define QUP_OUT_FIFO_BASE 0x110 @@ -44,6 +50,7 @@ #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 #define QUP_I2C_MASTER_GEN 0x408 +#define QUP_I2C_MASTER_CONFIG 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -53,6 +60,7 @@ #define QUP_STATE_VALIDBIT(2) #define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) #define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_I2C_STATUS_RESET 0xfc @@ -78,7 +86,10 @@ /* Packing/Unpacking words in FIFOs, and IO modes */ #define QUP_OUTPUT_BLK_MODE(1 << 10) +#define QUP_OUTPUT_BAM_MODE(3 << 10) #define QUP_INPUT_BLK_MODE (1 << 12) +#define QUP_INPUT_BAM_MODE (3 << 12) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) #define QUP_UNPACK_EN BIT(14) #define QUP_PACK_ENBIT(15) @@ -105,6 +116,10 @@ #define QUP_TAG_V2_DATARD 0x85 #define QUP_TAG_V2_DATARD_STOP 0x87 +/* QUP BAM v2 tags */ +#define QUP_BAM_INPUT_EOT 0x93 +#define QUP_BAM_FLUSH_STOP 0x96 + /* frequency definitions for high speed and max speed */ #define I2C_QUP_CLK_FAST_FREQ 100 #define I2C_QUP_CLK_MAX_FREQ 340 @@ -116,12 +131,21 @@ #define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_READ_LIMIT 256 +#define MX_TX_RX_LEN SZ_64K +#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) + +#define TOUT_MAX 300 /* Max timeout for 32k tx/tx */ struct qup_i2c_config { int tag_ver; int max_freq; }; +struct tag { + u8 *start; + dma_addr_t addr; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -157,9 +181,35 @@ struct qup_i2c_dev { /* QUP core errors */ u32 qup_err; + /* dma parameters */ + boolis_dma; + struct dma_pool *dpool; + struct tag start_tag; + struct tag scratch_tag; + struct tag footer_tag; + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; + struct scatterlist *sg_tx; + struct scatterlist *sg_rx; + dma_addr_t sg_tx_phys; + dma_addr_t sg_rx_phys; + struct completion xfer; }; +struct i2c_bam_xfer { + struct qup_i2c_dev *qup; + u32 start_len; + + u32 rx_nents; + u32 tx_nents; + + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t tx_cookie; + struct dma_async_tx_descriptor *rx_desc; + dma_cookie_t rx_cookie; +}; + static irqreturn_t qup_i2c_interrupt(int irq, void *dev) { struct qup_i2c_dev *qup = dev; @@ -233,6 +283,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); } +static void qup_i2c_flush(struct qup_i2c_dev *qup) +{ + u32 val = readl(qup->base + QUP_STATE); + + val |= QUP_I2C_FLUSH; + writel(val, qup->base + QUP_STATE); +} + static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) { return qup_i2c_poll_state_mask(qup, 0, 0); @@ -719,12 +777,244 @@ err: return ret; } +static void bam_i2c_callback(void *data) +{ + struct qup_i2c_dev *qup = data; + + complete(&qup->xfer); +} + +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last, + int blen) +{ + u8 addr = (msg->addr << 1) | ((msg->flags &
[PATCH 2/6] i2c: qup: Add V2 tags support
From: Andy Gross QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports bam dma and transfers of more than 256 bytes without 'stop' in between. Adding the support for the same. For each block a data_write/read tag and data_len tag is added to the output fifo. For the final block of data write_stop/read_stop tag is used. Signed-off-by: Andy Gross Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 342 ++- 1 file changed, 305 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 49c6cba..e4e223f 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -24,6 +24,7 @@ #include #include #include +#include /* QUP Registers */ #define QUP_CONFIG 0x000 @@ -42,6 +43,7 @@ #define QUP_IN_FIFO_BASE 0x218 #define QUP_I2C_CLK_CTL0x400 #define QUP_I2C_STATUS 0x404 +#define QUP_I2C_MASTER_GEN 0x408 /* QUP States and reset values */ #define QUP_RESET_STATE0 @@ -69,6 +71,8 @@ #define QUP_CLOCK_AUTO_GATEBIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 +#define I2C_N_VAL_V2 7 + /* Most significant word offset in FIFO port */ #define QUP_MSW_SHIFT (I2C_N_VAL + 1) @@ -80,17 +84,31 @@ #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 + #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_FIFO_SIZE(x)(((x) >> 2) & 0x07) #define QUP_INPUT_BLOCK_SIZE(x)(((x) >> 5) & 0x03) #define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07) -/* QUP tags */ +/* QUP V1 tags */ #define QUP_TAG_START (1 << 8) #define QUP_TAG_DATA (2 << 8) #define QUP_TAG_STOP (3 << 8) #define QUP_TAG_REC(4 << 8) +/* QUP v2 tags */ +#define QUP_TAG_V2_HS 0xff +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_STOP 0x87 + +/* frequency definitions for high speed and max speed */ +#define I2C_QUP_CLK_FAST_FREQ 100 +#define I2C_QUP_CLK_MAX_FREQ 340 + /* Status, Error flags */ #define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_BUS_ACTIVE BIT(8) @@ -99,6 +117,11 @@ #define QUP_READ_LIMIT 256 +struct qup_i2c_config { + int tag_ver; + int max_freq; +}; + struct qup_i2c_dev { struct device *dev; void __iomem*base; @@ -112,9 +135,20 @@ struct qup_i2c_dev { int in_fifo_sz; int out_blk_sz; int in_blk_sz; - + int blocks; + u8 *block_tag_len; + int *block_data_len; + int block_pos; unsigned long one_byte_t; + int is_hs; + booluse_v2_tags; + + int tx_tag_len; + int rx_tag_len; + u8 *tags; + int tags_pos; + struct i2c_msg *msg; /* Current posion in user message buffer */ int pos; @@ -262,8 +296,13 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; + /* Total Number of entries to shift out, including the tags */ + int total; + + if (qup->use_v2_tags) + total = msg->len + qup->tx_tag_len; + else + total = msg->len + 1; /* plus start tag */ if (total < qup->out_fifo_sz) { /* FIFO mode */ @@ -277,7 +316,7 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } -static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr = msg->addr << 1; u32 qup_tag; @@ -318,6 +357,136 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) } } +static void qup_i2c_create_tag_v2(struct qup_i2c_dev *qup, + struct i2c_msg *msg) +{ + u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD
[PATCH 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
The definition of i2c_msg says that "If this is the last message in a group, it is followed by a STOP. Otherwise it is followed by the next @i2c_msg transaction segment, beginning with a (repeated) START" So the expectation is that there is no 'STOP' bit inbetween individual i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way to inform that there should not be a 'STOP' at the end of transaction. The only way to implement this is to coalesce all the i2c_msg in i2c_msgs in to one transaction and transfer them. Adding the support for the same. This is required for some clients like touchscreen which keeps incrementing counts across individual transfers and 'STOP' bit inbetween resets the counter, which is not required. Signed-off-by: Sricharan R --- drivers/i2c/busses/i2c-qup.c | 192 ++- 1 file changed, 115 insertions(+), 77 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 11ea6af..90a2b5e 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -846,75 +846,91 @@ void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg, sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start); } -static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, int num) { struct dma_async_tx_descriptor *txd, *rxd = NULL; int ret = 0; dma_cookie_t cookie_rx, cookie_tx; - u32 rx_nents = 0, tx_nents = 0, len = 0; - /* QUP I2C read/write limit for single command is 256bytes max*/ - int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; - int rem = msg->len % QUP_READ_LIMIT; - int tlen, i = 0, tx_len = 0; - - if (msg->flags & I2C_M_RD) { - tx_nents = 1; - rx_nents = (blocks << 1) + 1; - sg_init_table(qup->sg_rx, rx_nents); - - while (i < blocks) { - /* transfer length set to '0' implies 256 bytes */ - tlen = (i == (blocks - 1)) ? rem : 0; - len += get_start_tag(&qup->start_tag.start[len], - msg, !i, (i == (blocks-1)), - tlen); - - qup_sg_set_buf(&qup->sg_rx[i << 1], - &qup->scratch_tag.start[0], - &qup->scratch_tag, - 2, qup, 0, 0); - - qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], - NULL, tlen, qup, 1, - DMA_FROM_DEVICE); - - i++; - } - - sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len); - qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0], - &qup->start_tag, len, qup, 0, 0); - qup_sg_set_buf(&qup->sg_rx[i << 1], - &qup->scratch_tag.start[1], - &qup->scratch_tag, 2, - qup, 0, 0); - } else { - qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP; - qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP; - - tx_nents = (blocks << 1) + 1; - sg_init_table(qup->sg_tx, tx_nents); - - while (i < blocks) { - tlen = (i == (blocks - 1)) ? rem : 0; - len = get_start_tag(&qup->start_tag.start[tx_len], - msg, !i, (i == (blocks-1)), tlen); - - qup_sg_set_buf(&qup->sg_tx[i << 1], - &qup->start_tag.start[tx_len], - &qup->start_tag, - len, qup, 0, 0); - - tx_len += len; - qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1], - &msg->buf[QUP_READ_LIMIT * i], NULL, - tlen, qup, 1, DMA_TO_DEVICE); - i++; + u32 rx_nents = 0, tx_nents = 0, len, blocks, rem, last; + u32 cur_rx_nents, cur_tx_nents; + u32 tlen, i, tx_len, tx_buf = 0, rx_buf = 0, off = 0; + + while (num) { + blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT; + rem = msg->len % QUP_READ_LIMIT; + i = 0, tx_len = 0, len = 0; + +
[PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
Signed-off-by: Sricharan R --- arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 3f648ae..1ec7ec5 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -246,6 +246,8 @@ clock-names = "core", "iface"; #address-cells = <1>; #size-cells = <0>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "bam-tx", "bam-rx"; }; blsp2_dma: dma@f9944000 { -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/6] i2c: qup: Add support for v2 tags and bam dma
QUP from version 2.1.1 onwards, supports a new format of i2c command tags. Tag codes instructs the controller to perform a operation like read/write. This new tagging version supports and is required for adding bam dma capabilities. v2 tags supports transfer of more than 256 bytes in a single i2c transaction. Also adding bam dma support facilitates transferring each i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some of the clients. This series depends on the below bam dma bug fix https://lkml.org/lkml/2015/2/20/47 Tested this series on apq8074 dragon board eeprom client on i2c bus1 Andy Gross (1): i2c: qup: Add V2 tags support Sricharan R (5): i2c: qup: Change qup_wait_writeready function to use for all timeouts i2c: qup: Add bam dma capabilities i2c: qup: Transfer every i2c_msg in i2c_msgs without stop dts: msm8974: Add blsp2_bam dma node dts: msm8974: Add dma channels for blsp2_i2c1 node arch/arm/boot/dts/qcom-msm8974.dtsi | 12 + drivers/i2c/busses/i2c-qup.c| 783 +--- 2 files changed, 741 insertions(+), 54 deletions(-) -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html