Merge "i2c: i2c-msm-geni: Framework to have test bus dump support"

This commit is contained in:
qctecmdr 2023-09-25 23:24:54 -07:00 committed by Gerrit - the friendly Code Review server
commit 912f91376c
2 changed files with 126 additions and 0 deletions

View File

@ -26,6 +26,9 @@
#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>
#define SE_GENI_TEST_BUS_CTRL 0x44
#define SE_NUM_FOR_TEST_BUS 5
#define SE_GENI_CFG_REG68 (0x210)
#define SE_I2C_TX_TRANS_LEN (0x26C)
#define SE_I2C_RX_TRANS_LEN (0x270)
@ -213,6 +216,7 @@ struct geni_i2c_dev {
bool skip_bw_vote; /* Used for PMIC over i2c use case to skip the BW vote */
atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */
bool bus_recovery_enable; /* To be enabled by client if needed */
bool i2c_test_dev; /* Set this DT flag to enable test bus dump for an SE */
};
static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
@ -412,6 +416,21 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c)
__func__, xfer_max_usec, gi2c->xfer_timeout);
}
/*
* geni_se_select_test_bus: Selects the test bus as required
*
* @gi2c_dev: Geni I2C device handle
* test_bus_num: Test bus number to select (1 to 16)
*
* Return: Nogeni_se_select_test_busne
*/
static void geni_se_select_test_bus(struct geni_i2c_dev *gi2c, u8 test_bus_num)
{
I2C_LOG_DBG(gi2c->ipcl, false, gi2c->dev,
"%s: test_bus:%d\n", __func__, test_bus_num);
writel_relaxed(test_bus_num, gi2c->base + SE_GENI_TEST_BUS_CTRL);
}
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
if (err == I2C_DATA_NACK || err == I2C_ADDR_NACK
@ -428,6 +447,33 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
gi2c->err = gi2c_log[err].err;
}
/*
* geni_i2c_test_bus_dump(): Dumps or reads test bus for selected SE test bus.
*
* @gi2c_i2c_dev: Handle to SE device
* @se_num: SE number, which start from 0.
*
* Return: None
*
* Note: This function has added extra test buses for refrences.
*/
static void geni_i2c_test_bus_dump(struct geni_i2c_dev *gi2c, u8 se_num)
{
/* Select test bus number and test bus, then read test bus.*/
/* geni_m_comp_sig_test_bus */
geni_se_select_test_bus(gi2c, 8);
test_bus_select_per_qupv3(gi2c->wrapper_dev, se_num, gi2c->ipcl);
test_bus_read_per_qupv3(gi2c->wrapper_dev, gi2c->ipcl);
/* geni_m_branch_cond_1_test_bus */
geni_se_select_test_bus(gi2c, 5);
test_bus_select_per_qupv3(gi2c->wrapper_dev, se_num, gi2c->ipcl);
test_bus_read_per_qupv3(gi2c->wrapper_dev, gi2c->ipcl);
/* Can Add more here based on debug ask. */
}
static void do_reg68_war_for_rtl_se(struct geni_i2c_dev *gi2c)
{
u32 status;
@ -469,6 +515,11 @@ static int geni_i2c_stop_with_cancel(struct geni_i2c_dev *gi2c)
{
int timeout = 0;
/* Issue point for e.g.: dump test bus/read test bus */
if (gi2c->i2c_test_dev)
/* For se4, its 5 as SE num starts from 0 */
geni_i2c_test_bus_dump(gi2c, SE_NUM_FOR_TEST_BUS);
reinit_completion(&gi2c->m_cancel_cmd);
geni_se_cancel_m_cmd(&gi2c->i2c_rsc);
timeout = wait_for_completion_timeout(&gi2c->m_cancel_cmd, HZ);
@ -2290,6 +2341,12 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (of_property_read_bool(pdev->dev.of_node, "qcom,leica-used-i2c"))
gi2c->skip_bw_vote = true;
gi2c->i2c_test_dev = false;
if (of_property_read_bool(pdev->dev.of_node, "qcom,i2c-test-dev")) {
gi2c->i2c_test_dev = true;
dev_info(&pdev->dev, "%s: This is I2C device under test\n", __func__);
}
gi2c->i2c_rsc.dev = dev;
gi2c->i2c_rsc.wrapper = dev_get_drvdata(dev->parent);
gi2c->i2c_rsc.base = gi2c->base;
@ -2382,6 +2439,11 @@ static int geni_i2c_probe(struct platform_device *pdev)
}
atomic_set(&gi2c->is_xfer_in_progress, 0);
if (gi2c->i2c_test_dev) {
/* configure Test bus to dump test bus later, only once */
test_bus_enable_per_qupv3(gi2c->wrapper_dev, gi2c->ipcl);
}
dev_info(gi2c->dev, "I2C probed\n");
return 0;
}

View File

@ -10,6 +10,7 @@
#include <linux/dma-direction.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/ipc_logging.h>
#ifdef CONFIG_ARM64
#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
@ -19,6 +20,10 @@
#define GENI_SE_DMA_PTR_H(ptr) 0
#endif
#define QUPV3_TEST_BUS_EN 0x204 //write 0x11
#define QUPV3_TEST_BUS_SEL 0x200 //write 0x5 [for SE index 4)
#define QUPV3_TEST_BUS_REG 0x208 //Read only reg, to be read as part of dump
#define GENI_SE_ERR(log_ctx, print, dev, x...) do { \
ipc_log_string(log_ctx, x); \
if (print) { \
@ -385,5 +390,64 @@ static inline void geni_se_common_get_major_minor_num(u32 hw_version,
*minor = (hw_version & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT;
*step = hw_version & HW_VER_STEP_MASK;
}
/*
* test_bus_enable_per_qupv3: enables particular test bus number.
* @wrapper_dev: QUPV3 common driver handle from SE driver
*
* Note: Need to call only once.
*
* Return: none
*/
static inline void test_bus_enable_per_qupv3(struct device *wrapper_dev, void *ipc)
{
struct geni_se *geni_se_dev;
geni_se_dev = dev_get_drvdata(wrapper_dev);
//Enablement of test bus is required only once.
//TEST_BUS_EN:4, TEST_BUS_REG_EN:0
geni_write_reg(0x11, geni_se_dev->base, QUPV3_TEST_BUS_EN);
GENI_SE_ERR(ipc, false, geni_se_dev->dev,
"%s: TEST_BUS_EN: 0x%x @address:0x%x\n",
__func__, geni_read_reg(geni_se_dev->base, QUPV3_TEST_BUS_EN),
(geni_se_dev->base + QUPV3_TEST_BUS_EN));
}
/*
* test_bus_select_per_qupv3: Selects the test bus as required
* @wrapper_dev: QUPV3 common driver handle from SE driver
* @test_bus_num: GENI SE number from QUPV3 core. E.g. SE0 should pass value 1.
*
* @Return: None
*/
static inline void test_bus_select_per_qupv3(struct device *wrapper_dev, u8 test_bus_num, void *ipc)
{
struct geni_se *geni_se_dev;
geni_se_dev = dev_get_drvdata(wrapper_dev);
geni_write_reg(test_bus_num, geni_se_dev->base, QUPV3_TEST_BUS_SEL);
GENI_SE_ERR(ipc, false, geni_se_dev->dev,
"%s: readback TEST_BUS_SEL: 0x%x @address:0x%x\n",
__func__, geni_read_reg(geni_se_dev->base, QUPV3_TEST_BUS_SEL),
(geni_se_dev->base + QUPV3_TEST_BUS_SEL));
}
/*
* test_bus_read_per_qupv3: Selects the test bus as required
* @wrapper_dev: QUPV3 common driver handle from SE driver
*
* Return: None
*/
static inline void test_bus_read_per_qupv3(struct device *wrapper_dev, void *ipc)
{
struct geni_se *geni_se_dev;
geni_se_dev = dev_get_drvdata(wrapper_dev);
GENI_SE_ERR(ipc, false, geni_se_dev->dev,
"%s: dump QUPV3_TEST_BUS_REG:0x%x\n",
__func__, geni_read_reg(geni_se_dev->base, QUPV3_TEST_BUS_REG));
}
#endif