Merge "i2c: i2c-msm-geni: Framework to have test bus dump support"
This commit is contained in:
commit
912f91376c
@ -26,6 +26,9 @@
|
|||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/slab.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_GENI_CFG_REG68 (0x210)
|
||||||
#define SE_I2C_TX_TRANS_LEN (0x26C)
|
#define SE_I2C_TX_TRANS_LEN (0x26C)
|
||||||
#define SE_I2C_RX_TRANS_LEN (0x270)
|
#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 */
|
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 */
|
atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */
|
||||||
bool bus_recovery_enable; /* To be enabled by client if needed */
|
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];
|
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);
|
__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)
|
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
|
||||||
{
|
{
|
||||||
if (err == I2C_DATA_NACK || err == I2C_ADDR_NACK
|
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;
|
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)
|
static void do_reg68_war_for_rtl_se(struct geni_i2c_dev *gi2c)
|
||||||
{
|
{
|
||||||
u32 status;
|
u32 status;
|
||||||
@ -469,6 +515,11 @@ static int geni_i2c_stop_with_cancel(struct geni_i2c_dev *gi2c)
|
|||||||
{
|
{
|
||||||
int timeout = 0;
|
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);
|
reinit_completion(&gi2c->m_cancel_cmd);
|
||||||
geni_se_cancel_m_cmd(&gi2c->i2c_rsc);
|
geni_se_cancel_m_cmd(&gi2c->i2c_rsc);
|
||||||
timeout = wait_for_completion_timeout(&gi2c->m_cancel_cmd, HZ);
|
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"))
|
if (of_property_read_bool(pdev->dev.of_node, "qcom,leica-used-i2c"))
|
||||||
gi2c->skip_bw_vote = true;
|
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.dev = dev;
|
||||||
gi2c->i2c_rsc.wrapper = dev_get_drvdata(dev->parent);
|
gi2c->i2c_rsc.wrapper = dev_get_drvdata(dev->parent);
|
||||||
gi2c->i2c_rsc.base = gi2c->base;
|
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);
|
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");
|
dev_info(gi2c->dev, "I2C probed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/dma-direction.h>
|
#include <linux/dma-direction.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/ipc_logging.h>
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64
|
#ifdef CONFIG_ARM64
|
||||||
#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
|
#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
|
||||||
@ -19,6 +20,10 @@
|
|||||||
#define GENI_SE_DMA_PTR_H(ptr) 0
|
#define GENI_SE_DMA_PTR_H(ptr) 0
|
||||||
#endif
|
#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 { \
|
#define GENI_SE_ERR(log_ctx, print, dev, x...) do { \
|
||||||
ipc_log_string(log_ctx, x); \
|
ipc_log_string(log_ctx, x); \
|
||||||
if (print) { \
|
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;
|
*minor = (hw_version & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT;
|
||||||
*step = hw_version & HW_VER_STEP_MASK;
|
*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
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user