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/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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user