[PATCH 1/2] i2c: Add support for Qualcomm Generic Interface (GENI) I2C controller

Neil Armstrong neil.armstrong at linaro.org
Mon Apr 22 11:23:40 CEST 2024


On 19/04/2024 13:47, Caleb Connolly wrote:
> Hi Neil,
> 
> On 18/04/2024 23:47, Neil Armstrong wrote:
>> Add Support for the Qualcomm Generic Interface (GENI) I2C interface
>> found on newer Qualcomm SoCs.
> 
> \o/
>>
>> The Generic Interface (GENI) is a firmware based Qualcomm Universal
>> Peripherals (QUP) Serial Engine (SE) Wrapper which can support multiple
>> bus protocols depending on the firmware type loaded at early boot time
>> based on system configuration.
>>
>> It also supports the "I2C Master Hub" which is a single function Wrapper
>> that only FIFO mode I2C.
>>
>> It replaces the fixed-function QUP Wrapper found on older SoCs.
>>
>> The geni-se.h containing the generic GENI Serial Engine registers defines
>> is imported from Linux.
>>
>> Only FIFO mode is implemented, nor SE DMA nor GPI DMA is implemented.
> nit: "neither SE DMA nor GPI DMA are implemented"

Thx!

> 
> A few minor things below, but otherwise LGTM!
>>
>> Signed-off-by: Neil Armstrong <neil.armstrong at linaro.org>
>> ---
>>   drivers/i2c/Kconfig        |  10 +
>>   drivers/i2c/Makefile       |   1 +
>>   drivers/i2c/geni_i2c.c     | 576 +++++++++++++++++++++++++++++++++++++++++++++
>>   include/soc/qcom/geni-se.h | 265 +++++++++++++++++++++
>>   4 files changed, 852 insertions(+)
>>
> [...]
>> diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c
>> new file mode 100644
>> index 00000000000..8c3ed3bef89
>> --- /dev/null
>> +++ b/drivers/i2c/geni_i2c.c
>> @@ -0,0 +1,576 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2024, Linaro Limited
>> + * Author: Neil Armstrong <neil.armstrong at linaro.org>
>> + *
>> + * Based on Linux driver: drivers/i2c/busses/i2c-qcom-geni.c
>> + */
>> +
> [...]
>> +static int geni_i2c_fifo_tx_fill(struct geni_i2c_priv *geni, struct i2c_msg *msg)
>> +{
>> +	ulong start = get_timer(0);
>> +	ulong cur_xfer = 0;
>> +	int i;
>> +
>> +	while (get_timer(start) < I2C_TIMEOUT_MS) {
>> +		u32 status = readl(geni->base + SE_GENI_M_IRQ_STATUS);
>> +
>> +		if (status & (M_CMD_ABORT_EN |
>> +			      M_CMD_OVERRUN_EN |
>> +			      M_ILLEGAL_CMD_EN |
>> +			      M_CMD_FAILURE_EN |
>> +			      M_GP_IRQ_1_EN |
>> +			      M_GP_IRQ_3_EN |
>> +			      M_GP_IRQ_4_EN)) {
>> +			debug("%s:%d cmd err\n", __func__, __LINE__);
> 
> How likely are we to hit this? Would it make sense to promote it to a
> pr_warn()?
> 
> Please drop the __LINE__ and (if it makes sense to?) print the value of
> status.

It's used when the tranactions is nacked, so it would spam, so I rather remove
the print entirely. It's verly unlikely we see any of the other errors.

>> +			writel(status, geni->base + SE_GENI_M_IRQ_CLEAR);
>> +			writel(0, geni->base + SE_GENI_TX_WATERMARK_REG);
>> +			return -EREMOTEIO;
>> +		}
>> +
>> +		if ((status & M_TX_FIFO_WATERMARK_EN) == 0) {
>> +			udelay(1);
>> +			goto skip_fill;
>> +		}
>> +
>> +		for (i = 0; i < geni->tx_wm; i++) {
>> +			u32 temp, tx = 0;
>> +			unsigned int p = 0;
>> +
>> +			while (cur_xfer < msg->len && p < sizeof(tx)) {
>> +				temp = msg->buf[cur_xfer++];
>> +				tx |= temp << (p * 8);
>> +				p++;
>> +			}
>> +
>> +			writel(tx, geni->base + SE_GENI_TX_FIFOn);
>> +
>> +			if (cur_xfer == msg->len) {
>> +				writel(0, geni->base + SE_GENI_TX_WATERMARK_REG);
>> +				break;
>> +			}
>> +		}
>> +
>> +skip_fill:
>> +		writel(status, geni->base + SE_GENI_M_IRQ_CLEAR);
>> +
>> +		if (status & M_CMD_DONE_EN)
>> +			return 0;
>> +	}
>> +
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int geni_i2c_fifo_rx_drain(struct geni_i2c_priv *geni, struct i2c_msg *msg)
>> +{
>> +	ulong start = get_timer(0);
>> +	ulong cur_xfer = 0;
>> +	int i;
>> +
>> +	while (get_timer(start) < I2C_TIMEOUT_MS) {
>> +		u32 status = readl(geni->base + SE_GENI_M_IRQ_STATUS);
>> +		u32 rxstatus = readl(geni->base + SE_GENI_RX_FIFO_STATUS);
>> +		u32 rxcnt = rxstatus & RX_FIFO_WC_MSK;
>> +
>> +		if (status & (M_CMD_ABORT_EN |
>> +			      M_CMD_FAILURE_EN |
>> +			      M_CMD_OVERRUN_EN |
>> +			      M_ILLEGAL_CMD_EN |
>> +			      M_GP_IRQ_1_EN |
>> +			      M_GP_IRQ_3_EN |
>> +			      M_GP_IRQ_4_EN)) {
>> +			debug("%s:%d cmd err\n", __func__, __LINE__);
> 
> Ditto
>> +			writel(status, geni->base + SE_GENI_M_IRQ_CLEAR);
>> +			return -EIO;
>> +		}
>> +
>> +		if ((status & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) == 0) {
>> +			udelay(1);
>> +			goto skip_drain;
>> +		}
>> +
>> +		for (i = 0; cur_xfer < msg->len && i < rxcnt; i++) {
>> +			u32 rx = readl(geni->base + SE_GENI_RX_FIFOn);
>> +			unsigned int p = 0;
>> +
>> +			while (cur_xfer < msg->len && p < sizeof(rx)) {
>> +				msg->buf[cur_xfer++] = rx & 0xff;
>> +				rx >>= 8;
>> +				p++;
>> +			}
>> +		}
>> +
>> +skip_drain:
>> +		writel(status, geni->base + SE_GENI_M_IRQ_CLEAR);
>> +
>> +		if (status & M_CMD_DONE_EN)
>> +			return 0;
>> +	}
>> +
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int geni_i2c_xfer_tx(struct geni_i2c_priv *geni, struct i2c_msg *msg, u32 params)
>> +{
>> +	writel(msg->len, geni->base + SE_I2C_TX_TRANS_LEN);
>> +	geni_i2c_setup_m_cmd(geni, I2C_WRITE, params);
>> +	writel(1, geni->base + SE_GENI_TX_WATERMARK_REG);
>> +
>> +	return geni_i2c_fifo_tx_fill(geni, msg);
>> +}
>> +
>> +static int geni_i2c_xfer_rx(struct geni_i2c_priv *geni, struct i2c_msg *msg, u32 params)
>> +{
>> +	writel(msg->len, geni->base + SE_I2C_RX_TRANS_LEN);
>> +	geni_i2c_setup_m_cmd(geni, I2C_READ, params);
>> +
>> +	return geni_i2c_fifo_rx_drain(geni, msg);
>> +}
>> +
>> +static int geni_i2c_xfer(struct udevice *bus, struct i2c_msg msgs[], int num)
>> +{
>> +	struct geni_i2c_priv *geni = dev_get_priv(bus);
>> +	int i, ret;
>> +
>> +	qcom_geni_i2c_conf(geni);
>> +
>> +	for (i = 0; i < num; i++) {
>> +		struct i2c_msg *msg = &msgs[i];
>> +		u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
>> +
>> +		m_param |= ((msg->addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
>> +
>> +		if (msg->flags & I2C_M_RD)
>> +			ret = geni_i2c_xfer_rx(geni, msg, m_param);
>> +		else
>> +			ret = geni_i2c_xfer_tx(geni, msg, m_param);
>> +
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	if (ret) {
>> +		if (ret == -ETIMEDOUT) {
>> +			u32 status;
>> +
>> +			writel(M_GENI_CMD_ABORT, geni->base + SE_GENI_M_CMD_CTRL_REG);
>> +
>> +			/* Wait until Abort has finished */
>> +			do {
>> +				status = readl(geni->base + SE_GENI_M_IRQ_STATUS);
>> +			} while ((status & M_CMD_ABORT_EN) == 0);
>> +
>> +			writel(status, geni->base + SE_GENI_M_IRQ_STATUS);
>> +		}
>> +
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int geni_i2c_enable_clocks(struct udevice *dev, struct geni_i2c_priv *geni)
>> +{
>> +	int ret;
>> +
>> +	if (geni->is_master_hub) {
>> +		ret = clk_enable(&geni->core);
>> +		if (ret) {
>> +			dev_err(dev, "clk_enable core failed %d\n", ret);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	ret = clk_enable(&geni->se);
>> +	if (ret) {
>> +		dev_err(dev, "clk_enable se failed %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int geni_i2c_disable_clocks(struct udevice *dev, struct geni_i2c_priv *geni)
>> +{
>> +	int ret;
>> +
>> +	if (geni->is_master_hub) {
>> +		ret = clk_disable(&geni->core);
>> +		if (ret) {
>> +			dev_err(dev, "clk_enable core failed %d\n", ret);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	ret = clk_disable(&geni->se);
>> +	if (ret) {
>> +		dev_err(dev, "clk_enable se failed %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +#define NUM_PACKING_VECTORS 4
>> +#define PACKING_START_SHIFT 5
>> +#define PACKING_DIR_SHIFT 4
>> +#define PACKING_LEN_SHIFT 1
>> +#define PACKING_STOP_BIT BIT(0)
>> +#define PACKING_VECTOR_SHIFT 10
>> +void geni_i2c_config_packing(struct geni_i2c_priv *geni, int bpw, int pack_words,
>> +			     bool msb_to_lsb, bool tx_cfg, bool rx_cfg)
>> +{
>> +	u32 cfg0, cfg1, cfg[NUM_PACKING_VECTORS] = {0};
>> +	int len;
>> +	int temp_bpw = bpw;
>> +	int idx_start = msb_to_lsb ? bpw - 1 : 0;
>> +	int idx = idx_start;
>> +	int idx_delta = msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE;
>> +	int ceil_bpw = ALIGN(bpw, BITS_PER_BYTE);
>> +	int iter = (ceil_bpw * pack_words) / BITS_PER_BYTE;
>> +	int i;
>> +
>> +	if (iter <= 0 || iter > NUM_PACKING_VECTORS)
>> +		return;
>> +
>> +	for (i = 0; i < iter; i++) {
>> +		len = min_t(int, temp_bpw, BITS_PER_BYTE) - 1;
>> +		cfg[i] = idx << PACKING_START_SHIFT;
>> +		cfg[i] |= msb_to_lsb << PACKING_DIR_SHIFT;
>> +		cfg[i] |= len << PACKING_LEN_SHIFT;
>> +
>> +		if (temp_bpw <= BITS_PER_BYTE) {
>> +			idx = ((i + 1) * BITS_PER_BYTE) + idx_start;
>> +			temp_bpw = bpw;
>> +		} else {
>> +			idx = idx + idx_delta;
>> +			temp_bpw = temp_bpw - BITS_PER_BYTE;
>> +		}
>> +	}
>> +	cfg[iter - 1] |= PACKING_STOP_BIT;
>> +	cfg0 = cfg[0] | (cfg[1] << PACKING_VECTOR_SHIFT);
>> +	cfg1 = cfg[2] | (cfg[3] << PACKING_VECTOR_SHIFT);
>> +
>> +	if (tx_cfg) {
>> +		writel(cfg0, geni->base + SE_GENI_TX_PACKING_CFG0);
>> +		writel(cfg1, geni->base + SE_GENI_TX_PACKING_CFG1);
>> +	}
>> +	if (rx_cfg) {
>> +		writel(cfg0, geni->base + SE_GENI_RX_PACKING_CFG0);
>> +		writel(cfg1, geni->base + SE_GENI_RX_PACKING_CFG1);
>> +	}
>> +
>> +	/*
>> +	 * Number of protocol words in each FIFO entry
>> +	 * 0 - 4x8, four words in each entry, max word size of 8 bits
>> +	 * 1 - 2x16, two words in each entry, max word size of 16 bits
>> +	 * 2 - 1x32, one word in each entry, max word size of 32 bits
>> +	 * 3 - undefined
>> +	 */
>> +	if (pack_words || bpw == 32)
>> +		writel(bpw / 16, geni->base + SE_GENI_BYTE_GRAN);
>> +}
>> +
>> +static void geni_i2c_init(struct geni_i2c_priv *geni, unsigned int tx_depth)
>> +{
>> +	u32 val;
>> +
>> +	writel(0, geni->base + SE_GSI_EVENT_EN);
>> +	writel(0xffffffff, geni->base + SE_GENI_M_IRQ_CLEAR);
>> +	writel(0xffffffff, geni->base + SE_GENI_S_IRQ_CLEAR);
>> +	writel(0xffffffff, geni->base + SE_IRQ_EN);
>> +
>> +	val = readl(geni->base + GENI_CGC_CTRL);
>> +	val |= DEFAULT_CGC_EN;
>> +	writel(val, geni->base + GENI_CGC_CTRL);
>> +
>> +	writel(DEFAULT_IO_OUTPUT_CTRL_MSK, geni->base + GENI_OUTPUT_CTRL);
>> +	writel(FORCE_DEFAULT, geni->base + GENI_FORCE_DEFAULT_REG);
>> +
>> +	val = readl(geni->base + SE_IRQ_EN);
>> +	val |= GENI_M_IRQ_EN | GENI_S_IRQ_EN;
>> +	writel(val, geni->base + SE_IRQ_EN);
>> +
>> +	val = readl(geni->base + SE_GENI_DMA_MODE_EN);
>> +	val &= ~GENI_DMA_MODE_EN;
>> +	writel(val, geni->base + SE_GENI_DMA_MODE_EN);
>> +
>> +	writel(0, geni->base + SE_GSI_EVENT_EN);
>> +
>> +	writel(tx_depth - 1, geni->base + SE_GENI_RX_WATERMARK_REG);
>> +	writel(tx_depth, geni->base + SE_GENI_RX_RFR_WATERMARK_REG);
>> +
>> +	val = readl(geni->base + SE_GENI_M_IRQ_EN);
>> +	val |= M_COMMON_GENI_M_IRQ_EN;
>> +	val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
>> +	val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
>> +	writel(val, geni->base + SE_GENI_M_IRQ_EN);
>> +
>> +	val = readl(geni->base + SE_GENI_S_IRQ_EN);
>> +	val |= S_COMMON_GENI_S_IRQ_EN;
>> +	writel(val, geni->base + SE_GENI_S_IRQ_EN);
>> +}
>> +
>> +static u32 geni_i2c_get_tx_fifo_depth(struct geni_i2c_priv *geni)
>> +{
>> +	u32 val, hw_version, hw_major, hw_minor, tx_fifo_depth_mask;
>> +
>> +	hw_version = readl(geni->wrapper + QUP_HW_VER_REG);
>> +	hw_major = GENI_SE_VERSION_MAJOR(hw_version);
>> +	hw_minor = GENI_SE_VERSION_MINOR(hw_version);
>> +
>> +	if ((hw_major == 3 && hw_minor >= 10) || hw_major > 3)
>> +		tx_fifo_depth_mask = TX_FIFO_DEPTH_MSK_256_BYTES;
>> +	else
>> +		tx_fifo_depth_mask = TX_FIFO_DEPTH_MSK;
>> +
>> +	val = readl(geni->base + SE_HW_PARAM_0);
>> +
>> +	return (val & tx_fifo_depth_mask) >> TX_FIFO_DEPTH_SHFT;
>> +}
>> +
>> +static int geni_i2c_probe(struct udevice *dev)
>> +{
>> +	ofnode parent_node = ofnode_get_parent(dev_ofnode(dev));
>> +	struct geni_i2c_priv *geni = dev_get_priv(dev);
>> +	u32 proto, tx_depth, fifo_disable;
>> +	int ret;
>> +
>> +	geni->is_master_hub = dev_get_driver_data(dev) & GENI_I2C_IS_MASTER_HUB;
>> +
>> +	geni->wrapper = ofnode_get_addr(parent_node);
>> +	if (geni->wrapper == FDT_ADDR_T_NONE)
>> +		return -EINVAL;
>> +
>> +	geni->base = (phys_addr_t)dev_read_addr_ptr(dev);
>> +	if (!geni->base)
>> +		return -EINVAL;
>> +
>> +	if (geni->is_master_hub) {
>> +		ret = clk_get_by_name(dev, "core", &geni->core);
>> +		if (ret) {
>> +			pr_err("clk_get_by_name(core) failed: %d\n", ret);
> 
> In other places you used dev_err(), but here it's pr_err() (even though
> dev is available), and below it's pr_err() with __func__ as the prefix.
> Please make these consistent.

Ack

>> +			return ret;
>> +		}
>> +	}
>> +
>> +	ret = clk_get_by_name(dev, "se", &geni->se);
>> +	if (ret) {
>> +		pr_err("clk_get_by_name(iface) failed: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	geni_i2c_enable_clocks(dev, geni);
>> +
>> +	proto = readl(geni->base + GENI_FW_REVISION_RO);
>> +	proto &= FW_REV_PROTOCOL_MSK;
>> +	proto >>= FW_REV_PROTOCOL_SHFT;
>> +
>> +	if (proto != GENI_SE_I2C) {
>> +		pr_err("%s: Invalid proto %d\n", __func__, proto);
>> +		geni_i2c_disable_clocks(dev, geni);
>> +		return -ENXIO;
>> +	}
>> +
>> +	fifo_disable = readl(geni->base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
>> +	if (fifo_disable) {
>> +		geni_i2c_disable_clocks(dev, geni);
>> +		pr_err("%s: FIFO mode disabled, DMA mode unsupported\n", __func__);
>> +		return -ENXIO;
>> +	}
>> +
>> +	if (!geni->is_master_hub) {
>> +		tx_depth = geni_i2c_get_tx_fifo_depth(geni);
>> +		if (!tx_depth) {
>> +			geni_i2c_disable_clocks(dev, geni);
>> +			pr_err("%s: Invalid TX FIFO depth\n", __func__);
>> +			return -ENXIO;
>> +		}
>> +	} else {
>> +		tx_depth = 16;
>> +	}
>> +	geni->tx_wm = tx_depth - 1;
>> +
>> +	geni_i2c_init(geni, tx_depth);
>> +	geni_i2c_config_packing(geni, BITS_PER_BYTE,
>> +				PACKING_BYTES_PW, true, true, true);
>> +
>> +	/* Setup for standard rate */
>> +	return geni_i2c_clk_map_idx(geni, I2C_SPEED_STANDARD_RATE);
>> +}
>> +
>> +static int geni_i2c_set_bus_speed(struct udevice *dev, unsigned int clk_freq)
>> +{
>> +	struct geni_i2c_priv *geni = dev_get_priv(dev);
>> +
>> +	return geni_i2c_clk_map_idx(geni, clk_freq);
>> +}
>> +
>> +static const struct dm_i2c_ops geni_i2c_ops = {
>> +	.xfer		= geni_i2c_xfer,
>> +	.set_bus_speed	= geni_i2c_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id geni_i2c_ids[] = {
>> +	{ .compatible = "qcom,geni-i2c" },
>> +	{ .compatible = "qcom,geni-i2c-master-hub", .data = GENI_I2C_IS_MASTER_HUB},
>> +	{}
>> +};
>> +
>> +U_BOOT_DRIVER(i2c_geni) = {
>> +	.name	= "i2c_geni",
>> +	.id	= UCLASS_I2C,
>> +	.of_match = geni_i2c_ids,
>> +	.probe	= geni_i2c_probe,
>> +	.priv_auto = sizeof(struct geni_i2c_priv),
>> +	.ops	= &geni_i2c_ops,
>> +};
>> +
>> +static const struct udevice_id geni_i2c_master_hub_ids[] = {
>> +	{ .compatible = "qcom,geni-se-i2c-master-hub" },
>> +	{ }
>> +};
>> +
>> +U_BOOT_DRIVER(geni_i2c_master_hub) = {
>> +	.name = "geni-se-master-hub",
>> +	.id = UCLASS_NOP,
>> +	.of_match = geni_i2c_master_hub_ids,
>> +	.bind = dm_scan_fdt_dev,
>> +	.flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
>> +};
>> diff --git a/include/soc/qcom/geni-se.h b/include/soc/qcom/geni-se.h
>> new file mode 100644
>> index 00000000000..698a9256d26
>> --- /dev/null
>> +++ b/include/soc/qcom/geni-se.h
>> @@ -0,0 +1,265 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
>> + */
>> +
>> +#ifndef _QCOM_GENI_SE
>> +#define _QCOM_GENI_SE
>> +
>> +/* Protocols supported by GENI Serial Engines */
>> +enum geni_se_protocol_type {
>> +	GENI_SE_NONE,
>> +	GENI_SE_SPI,
>> +	GENI_SE_UART,
>> +	GENI_SE_I2C,
>> +	GENI_SE_I3C,
>> +	GENI_SE_SPI_SLAVE,
>> +};
>> +
>> +#define QUP_HW_VER_REG			0x4
>> +
>> +/* Common SE registers */
>> +#define GENI_INIT_CFG_REVISION		0x0
>> +#define GENI_S_INIT_CFG_REVISION	0x4
>> +#define GENI_FORCE_DEFAULT_REG		0x20
>> +#define GENI_OUTPUT_CTRL		0x24
>> +#define GENI_CGC_CTRL			0x28
>> +#define SE_GENI_STATUS			0x40
>> +#define GENI_SER_M_CLK_CFG		0x48
>> +#define GENI_SER_S_CLK_CFG		0x4c
>> +#define GENI_IF_DISABLE_RO		0x64
>> +#define GENI_FW_REVISION_RO		0x68
>> +#define SE_GENI_CLK_SEL			0x7c
>> +#define SE_GENI_CFG_SEQ_START		0x84
>> +#define SE_GENI_BYTE_GRAN		0x254
>> +#define SE_GENI_DMA_MODE_EN		0x258
>> +#define SE_GENI_TX_PACKING_CFG0		0x260
>> +#define SE_GENI_TX_PACKING_CFG1		0x264
>> +#define SE_GENI_RX_PACKING_CFG0		0x284
>> +#define SE_GENI_RX_PACKING_CFG1		0x288
>> +#define SE_GENI_M_CMD0			0x600
>> +#define SE_GENI_M_CMD_CTRL_REG		0x604
>> +#define SE_GENI_M_IRQ_STATUS		0x610
>> +#define SE_GENI_M_IRQ_EN		0x614
>> +#define SE_GENI_M_IRQ_CLEAR		0x618
>> +#define SE_GENI_S_CMD0			0x630
>> +#define SE_GENI_S_CMD_CTRL_REG		0x634
>> +#define SE_GENI_S_IRQ_STATUS		0x640
>> +#define SE_GENI_S_IRQ_EN		0x644
>> +#define SE_GENI_S_IRQ_CLEAR		0x648
>> +#define SE_GENI_TX_FIFOn		0x700
>> +#define SE_GENI_RX_FIFOn		0x780
>> +#define SE_GENI_TX_FIFO_STATUS		0x800
>> +#define SE_GENI_RX_FIFO_STATUS		0x804
>> +#define SE_GENI_TX_WATERMARK_REG	0x80c
>> +#define SE_GENI_RX_WATERMARK_REG	0x810
>> +#define SE_GENI_RX_RFR_WATERMARK_REG	0x814
>> +#define SE_GENI_IOS			0x908
>> +#define SE_DMA_TX_IRQ_STAT		0xc40
>> +#define SE_DMA_TX_IRQ_CLR		0xc44
>> +#define SE_DMA_TX_FSM_RST		0xc58
>> +#define SE_DMA_RX_IRQ_STAT		0xd40
>> +#define SE_DMA_RX_IRQ_CLR		0xd44
>> +#define SE_DMA_RX_LEN_IN		0xd54
>> +#define SE_DMA_RX_FSM_RST		0xd58
>> +#define SE_GSI_EVENT_EN			0xe18
>> +#define SE_IRQ_EN			0xe1c
>> +#define SE_HW_PARAM_0			0xe24
>> +#define SE_HW_PARAM_1			0xe28
>> +
>> +/* GENI_FORCE_DEFAULT_REG fields */
>> +#define FORCE_DEFAULT	BIT(0)
>> +
>> +/* GENI_OUTPUT_CTRL fields */
>> +#define GENI_IO_MUX_0_EN		BIT(0)
>> +#define DEFAULT_IO_OUTPUT_CTRL_MSK	GENMASK(6, 0)
>> +
>> +/* GENI_CGC_CTRL fields */
>> +#define CFG_AHB_CLK_CGC_ON		BIT(0)
>> +#define CFG_AHB_WR_ACLK_CGC_ON		BIT(1)
>> +#define DATA_AHB_CLK_CGC_ON		BIT(2)
>> +#define SCLK_CGC_ON			BIT(3)
>> +#define TX_CLK_CGC_ON			BIT(4)
>> +#define RX_CLK_CGC_ON			BIT(5)
>> +#define EXT_CLK_CGC_ON			BIT(6)
>> +#define PROG_RAM_HCLK_OFF		BIT(8)
>> +#define PROG_RAM_SCLK_OFF		BIT(9)
>> +#define DEFAULT_CGC_EN			GENMASK(6, 0)
>> +
>> +/* GENI_STATUS fields */
>> +#define M_GENI_CMD_ACTIVE		BIT(0)
>> +#define S_GENI_CMD_ACTIVE		BIT(12)
>> +
>> +/* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
>> +#define SER_CLK_EN			BIT(0)
>> +#define CLK_DIV_MSK			GENMASK(15, 4)
>> +#define CLK_DIV_SHFT			4
>> +
>> +/* GENI_IF_DISABLE_RO fields */
>> +#define FIFO_IF_DISABLE			(BIT(0))
>> +
>> +/* GENI_FW_REVISION_RO fields */
>> +#define FW_REV_PROTOCOL_MSK		GENMASK(15, 8)
>> +#define FW_REV_PROTOCOL_SHFT		8
>> +
>> +/* GENI_CLK_SEL fields */
>> +#define CLK_SEL_MSK			GENMASK(2, 0)
>> +
>> +/* SE_GENI_CFG_SEQ_START fields */
>> +#define START_TRIGGER			BIT(0)
>> +
>> +/* SE_IRQ_EN fields */
>> +#define DMA_RX_IRQ_EN			BIT(0)
>> +#define DMA_TX_IRQ_EN			BIT(1)
>> +#define GENI_M_IRQ_EN			BIT(2)
>> +#define GENI_S_IRQ_EN			BIT(3)
>> +
>> +/* SE_GENI_DMA_MODE_EN */
>> +#define GENI_DMA_MODE_EN		BIT(0)
>> +
>> +/* GENI_M_CMD0 fields */
>> +#define M_OPCODE_MSK			GENMASK(31, 27)
>> +#define M_OPCODE_SHFT			27
>> +#define M_PARAMS_MSK			GENMASK(26, 0)
>> +
>> +/* GENI_M_CMD_CTRL_REG */
>> +#define M_GENI_CMD_CANCEL		BIT(2)
>> +#define M_GENI_CMD_ABORT		BIT(1)
>> +#define M_GENI_DISABLE			BIT(0)
>> +
>> +/* GENI_S_CMD0 fields */
>> +#define S_OPCODE_MSK			GENMASK(31, 27)
>> +#define S_OPCODE_SHFT			27
>> +#define S_PARAMS_MSK			GENMASK(26, 0)
>> +
>> +/* GENI_S_CMD_CTRL_REG */
>> +#define S_GENI_CMD_CANCEL		BIT(2)
>> +#define S_GENI_CMD_ABORT		BIT(1)
>> +#define S_GENI_DISABLE			BIT(0)
>> +
>> +/* GENI_M_IRQ_EN fields */
>> +#define M_CMD_DONE_EN			BIT(0)
>> +#define M_CMD_OVERRUN_EN		BIT(1)
>> +#define M_ILLEGAL_CMD_EN		BIT(2)
>> +#define M_CMD_FAILURE_EN		BIT(3)
>> +#define M_CMD_CANCEL_EN			BIT(4)
>> +#define M_CMD_ABORT_EN			BIT(5)
>> +#define M_TIMESTAMP_EN			BIT(6)
>> +#define M_RX_IRQ_EN			BIT(7)
>> +#define M_GP_SYNC_IRQ_0_EN		BIT(8)
>> +#define M_GP_IRQ_0_EN			BIT(9)
>> +#define M_GP_IRQ_1_EN			BIT(10)
>> +#define M_GP_IRQ_2_EN			BIT(11)
>> +#define M_GP_IRQ_3_EN			BIT(12)
>> +#define M_GP_IRQ_4_EN			BIT(13)
>> +#define M_GP_IRQ_5_EN			BIT(14)
>> +#define M_TX_FIFO_NOT_EMPTY_EN		BIT(21)
>> +#define M_IO_DATA_DEASSERT_EN		BIT(22)
>> +#define M_IO_DATA_ASSERT_EN		BIT(23)
>> +#define M_RX_FIFO_RD_ERR_EN		BIT(24)
>> +#define M_RX_FIFO_WR_ERR_EN		BIT(25)
>> +#define M_RX_FIFO_WATERMARK_EN		BIT(26)
>> +#define M_RX_FIFO_LAST_EN		BIT(27)
>> +#define M_TX_FIFO_RD_ERR_EN		BIT(28)
>> +#define M_TX_FIFO_WR_ERR_EN		BIT(29)
>> +#define M_TX_FIFO_WATERMARK_EN		BIT(30)
>> +#define M_SEC_IRQ_EN			BIT(31)
>> +#define M_COMMON_GENI_M_IRQ_EN	(GENMASK(6, 1) | \
>> +				M_IO_DATA_DEASSERT_EN | \
>> +				M_IO_DATA_ASSERT_EN | M_RX_FIFO_RD_ERR_EN | \
>> +				M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | \
>> +				M_TX_FIFO_WR_ERR_EN)
>> +
>> +/* GENI_S_IRQ_EN fields */
>> +#define S_CMD_DONE_EN			BIT(0)
>> +#define S_CMD_OVERRUN_EN		BIT(1)
>> +#define S_ILLEGAL_CMD_EN		BIT(2)
>> +#define S_CMD_FAILURE_EN		BIT(3)
>> +#define S_CMD_CANCEL_EN			BIT(4)
>> +#define S_CMD_ABORT_EN			BIT(5)
>> +#define S_GP_SYNC_IRQ_0_EN		BIT(8)
>> +#define S_GP_IRQ_0_EN			BIT(9)
>> +#define S_GP_IRQ_1_EN			BIT(10)
>> +#define S_GP_IRQ_2_EN			BIT(11)
>> +#define S_GP_IRQ_3_EN			BIT(12)
>> +#define S_GP_IRQ_4_EN			BIT(13)
>> +#define S_GP_IRQ_5_EN			BIT(14)
>> +#define S_IO_DATA_DEASSERT_EN		BIT(22)
>> +#define S_IO_DATA_ASSERT_EN		BIT(23)
>> +#define S_RX_FIFO_RD_ERR_EN		BIT(24)
>> +#define S_RX_FIFO_WR_ERR_EN		BIT(25)
>> +#define S_RX_FIFO_WATERMARK_EN		BIT(26)
>> +#define S_RX_FIFO_LAST_EN		BIT(27)
>> +#define S_COMMON_GENI_S_IRQ_EN	(GENMASK(5, 1) | GENMASK(13, 9) | \
>> +				 S_RX_FIFO_RD_ERR_EN | S_RX_FIFO_WR_ERR_EN)
>> +
>> +/*  GENI_/TX/RX/RX_RFR/_WATERMARK_REG fields */
>> +#define WATERMARK_MSK			GENMASK(5, 0)
>> +
>> +/* GENI_TX_FIFO_STATUS fields */
>> +#define TX_FIFO_WC			GENMASK(27, 0)
>> +
>> +/*  GENI_RX_FIFO_STATUS fields */
>> +#define RX_LAST				BIT(31)
>> +#define RX_LAST_BYTE_VALID_MSK		GENMASK(30, 28)
>> +#define RX_LAST_BYTE_VALID_SHFT		28
>> +#define RX_FIFO_WC_MSK			GENMASK(24, 0)
>> +
>> +/* SE_GENI_IOS fields */
>> +#define IO2_DATA_IN			BIT(1)
>> +#define RX_DATA_IN			BIT(0)
>> +
>> +/* SE_DMA_TX_IRQ_STAT Register fields */
>> +#define TX_DMA_DONE			BIT(0)
>> +#define TX_EOT				BIT(1)
>> +#define TX_SBE				BIT(2)
>> +#define TX_RESET_DONE			BIT(3)
>> +
>> +/* SE_DMA_RX_IRQ_STAT Register fields */
>> +#define RX_DMA_DONE			BIT(0)
>> +#define RX_EOT				BIT(1)
>> +#define RX_SBE				BIT(2)
>> +#define RX_RESET_DONE			BIT(3)
>> +#define RX_FLUSH_DONE			BIT(4)
>> +#define RX_DMA_PARITY_ERR		BIT(5)
>> +#define RX_DMA_BREAK			GENMASK(8, 7)
>> +#define RX_GENI_GP_IRQ			GENMASK(10, 5)
>> +#define RX_GENI_CANCEL_IRQ		BIT(11)
>> +#define RX_GENI_GP_IRQ_EXT		GENMASK(13, 12)
>> +
>> +/* SE_HW_PARAM_0 fields */
>> +#define TX_FIFO_WIDTH_MSK		GENMASK(29, 24)
>> +#define TX_FIFO_WIDTH_SHFT		24
>> +/*
>> + * For QUP HW Version >= 3.10 Tx fifo depth support is increased
>> + * to 256bytes and corresponding bits are 16 to 23
>> + */
>> +#define TX_FIFO_DEPTH_MSK_256_BYTES	GENMASK(23, 16)
>> +#define TX_FIFO_DEPTH_MSK		GENMASK(21, 16)
>> +#define TX_FIFO_DEPTH_SHFT		16
>> +
>> +/* SE_HW_PARAM_1 fields */
>> +#define RX_FIFO_WIDTH_MSK		GENMASK(29, 24)
>> +#define RX_FIFO_WIDTH_SHFT		24
>> +/*
>> + * For QUP HW Version >= 3.10 Rx fifo depth support is increased
>> + * to 256bytes and corresponding bits are 16 to 23
>> + */
>> +#define RX_FIFO_DEPTH_MSK_256_BYTES	GENMASK(23, 16)
>> +#define RX_FIFO_DEPTH_MSK		GENMASK(21, 16)
>> +#define RX_FIFO_DEPTH_SHFT		16
>> +
>> +#define HW_VER_MAJOR_MASK		GENMASK(31, 28)
>> +#define HW_VER_MAJOR_SHFT		28
>> +#define HW_VER_MINOR_MASK		GENMASK(27, 16)
>> +#define HW_VER_MINOR_SHFT		16
>> +#define HW_VER_STEP_MASK		GENMASK(15, 0)
>> +
>> +#define GENI_SE_VERSION_MAJOR(ver) ((ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT)
>> +#define GENI_SE_VERSION_MINOR(ver) ((ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT)
>> +#define GENI_SE_VERSION_STEP(ver) (ver & HW_VER_STEP_MASK)
>> +
>> +/* QUP SE VERSION value for major number 2 and minor number 5 */
>> +#define QUP_SE_VERSION_2_5                  0x20050000
>> +
>> +#endif
>>
> 

Thanks,
Neil


More information about the U-Boot mailing list