diff --git a/drivers/mfd/rkx110_x120/rkx110_linktx.c b/drivers/mfd/rkx110_x120/rkx110_linktx.c index 59135a990deb..3052dac553b6 100644 --- a/drivers/mfd/rkx110_x120/rkx110_linktx.c +++ b/drivers/mfd/rkx110_x120/rkx110_linktx.c @@ -101,7 +101,33 @@ #define SER_RKLINK_AUDIO_RECOVER LINK_REG(0x0034) #define SER_RKLINK_AUDIO_FM_STATUS LINK_REG(0x0038) #define SER_RKLINK_FIFO_STATUS LINK_REG(0x003C) + #define CH1_CMD_FIFO_UNDERRUN BIT(24) + #define CH0_CMD_FIFO_UNDERRUN BIT(23) + #define DATA1_FIFO_UNDERRUN BIT(22) + #define DATA0_FIFO_UNDERRUN BIT(21) + #define AUDIO_FIFO_UNDERRUN BIT(20) + #define LVDS1_FIFO_UNDERRUN BIT(19) + #define LVDS0_FIFO_UNDERRUN BIT(18) + #define DSI_CH1_FIFO_UNDERRUN BIT(17) + #define DSI_CH0_FIFO_UNDERRUN BIT(16) + #define CH1_CMD_FIFO_OVERFLOW BIT(8) + #define CH0_CMD_FIFO_OVERFLOW BIT(7) + #define DATA0_FIFO_OVERFLOW BIT(6) + #define DATA1_FIFO_OVERFLOW BIT(5) + #define AUDIO_FIFO_OVERFLOW BIT(4) + #define LVDS1_FIFO_OVERFLOW BIT(3) + #define LVDS0_FIFO_OVERFLOW BIT(2) + #define DSI_CH1_FIFO_OVERFLOW BIT(1) + #define DSI_CH0_FIFO_OVERFLOW BIT(0) #define SER_RKLINK_SOURCE_IRQ_EN LINK_REG(0x0040) + #define TRAIN_DONE_IRQ_FLAG BIT(19) + #define FIFO_UNDERRUN_IRQ_FLAG BIT(18) + #define FIFO_OVERFLOW_IRQ_FLAG BIT(17) + #define AUDIO_FM_IRQ_OUTPUT_FLAG BIT(16) + #define TRAIN_DONE_IRQ_OUTPUT_EN BIT(3) + #define FIFO_UNDERRUN_IRQ_OUTPUT_EN BIT(2) + #define FIFO_OVERFLOW_IRQ_OUTPUT_EN BIT(1) + #define AUDIO_FM_IRQ_OUTPUT_EN BIT(0) #define SER_RKLINK_TRAIN_CTRL LINK_REG(0x0044) #define SER_RKLINK_I2C_CFG LINK_REG(0x00C0) @@ -144,7 +170,9 @@ #define PCS_REG24(id) PCS_REG(id, 0x24) #define PCS_REG28(id) PCS_REG(id, 0x28) #define PCS_REG30(id) PCS_REG(id, 0x30) +#define PCS_INT_STARTUP(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0) #define PCS_REG34(id) PCS_REG(id, 0x34) +#define PCS_INT_REMOTE_MODE(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0) #define PCS_REG40(id) PCS_REG(id, 0x40) #define PMA_REG(id, x) ((x) + RKX110_SER_PMA0_BASE + (id) * RKX110_SER_PMA_OFFSET) @@ -195,6 +223,15 @@ #define PMA_CLK_8X_DIV_MASK HIWORD_MASK(7, 1) #define PMA_CLK_8X_DIV(x) HIWORD_UPDATE(x, GENMASK(7, 1), 1) +#define SER_PMA_IRQ_EN(id) PMA_REG(id, 0xF0) + #define FORCE_INITIAL_IRQ_EN HIWORD_UPDATE(1, BIT(3), 3) + #define RTERM_ONCE_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(1), 1) + #define PLL_LOCK_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(0), 0) +#define SER_PMA_IRQ_STATUS(id) PMA_REG(id, 0xF4) + #define FORCE_INITIAL_PULSE_STATUS BIT(3) + #define RTERM_ONCE_TIMEOUT_STATUS BIT(1) + #define PLL_LOCK_TIMEOUT_STATUS BIT(0) + enum { SER_LINK_CH_ID0 = 0, SER_LINK_CH_ID1, @@ -750,3 +787,346 @@ void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 serdes->i2c_update_bits(client, SER_GRF_SOC_CON7, mask, val); } + +static void rkx110_linktx_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_LINK_EN); + + serdes->i2c_write_reg(client, SER_RKLINK_SOURCE_IRQ_EN, TRAIN_DONE_IRQ_OUTPUT_EN | + FIFO_UNDERRUN_IRQ_OUTPUT_EN | FIFO_OVERFLOW_IRQ_OUTPUT_EN); +} + +static void rkx110_linktx_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_LINK_DIS); + serdes->i2c_read_reg(client, SER_RKLINK_SOURCE_IRQ_EN, &val); + val &= ~(SER_RKLINK_SOURCE_IRQ_EN | TRAIN_DONE_IRQ_OUTPUT_EN | + FIFO_UNDERRUN_IRQ_OUTPUT_EN | FIFO_OVERFLOW_IRQ_OUTPUT_EN); + serdes->i2c_write_reg(client, SER_RKLINK_SOURCE_IRQ_EN, val); +} + +static void rkx110_linktx_fifo_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, SER_RKLINK_FIFO_STATUS, &value); + dev_err(serdes->dev, "ser rklink fifo status:0x%x\n", value); + + if (value & CH1_CMD_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx ch1 cmd fifo underrun\n"); + if (value & CH0_CMD_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx ch0 cmd fifo underrun\n"); + if (value & DATA1_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx data1 fifo underrun\n"); + if (value & DATA0_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx data0 fifo underrun\n"); + if (value & AUDIO_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx audio fifo underrun\n"); + if (value & LVDS1_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx lvds1 fifo underrun\n"); + if (value & LVDS0_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx lvds0 fifo underrun\n"); + if (value & DSI_CH1_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx dsi ch1 fifo underrun\n"); + if (value & DSI_CH0_FIFO_UNDERRUN) + dev_err(serdes->dev, "linktx dsi ch0 fifo underrun\n"); + if (value & CH1_CMD_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx ch1 cmd fifo overflow\n"); + if (value & CH0_CMD_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx ch0 cmd fifo overflow\n"); + if (value & DATA1_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx data1 fifo overflow\n"); + if (value & DATA0_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx data0 fifo overflow\n"); + if (value & AUDIO_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx audio fifo overflow\n"); + if (value & LVDS1_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx lvds1 fifo overflow\n"); + if (value & LVDS0_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx lvds0 fifo overflow\n"); + if (value & DSI_CH1_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx dsi ch1 fifo overflow\n"); + if (value & DSI_CH0_FIFO_OVERFLOW) + dev_err(serdes->dev, "linktx dsi ch0 fifo overflow\n"); + + /* clear fifo status */ + serdes->i2c_write_reg(client, SER_RKLINK_FIFO_STATUS, value); +} + +static void rkx110_linktx_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 flag, value; + int i = 0; + + serdes->i2c_read_reg(client, SER_RKLINK_SOURCE_IRQ_EN, &flag); + flag &= TRAIN_DONE_IRQ_FLAG | FIFO_UNDERRUN_IRQ_FLAG | FIFO_OVERFLOW_IRQ_FLAG | + AUDIO_FM_IRQ_OUTPUT_FLAG; + dev_info(serdes->dev, "linktx irq flag:0x%08x\n", flag); + while (flag) { + switch (flag & BIT(i)) { + case TRAIN_DONE_IRQ_FLAG: + serdes->i2c_read_reg(client, SER_RKLINK_TRAIN_CTRL, &value); + dev_info(serdes->dev, "linktx train done, status:0x%08x\n", value); + /* write any thing to train ctrl will clear the train done irq flag */ + serdes->i2c_write_reg(client, SER_RKLINK_TRAIN_CTRL, value); + break; + case FIFO_UNDERRUN_IRQ_FLAG: + case FIFO_OVERFLOW_IRQ_FLAG: + flag &= ~(FIFO_UNDERRUN_IRQ_FLAG | FIFO_OVERFLOW_IRQ_FLAG); + rkx110_linktx_fifo_handler(serdes, dev_id); + break; + case AUDIO_FM_IRQ_OUTPUT_FLAG: + break; + default: + break; + } + flag &= ~BIT(i); + i++; + } +} + +static void rkx110_pcs_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + val = pcs_id ? SER_IRQ_PCS1_EN : SER_IRQ_PCS0_EN; + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, PCS_REG30(pcs_id), PCS_INT_STARTUP(0xffff)); + serdes->i2c_write_reg(client, PCS_REG34(pcs_id), PCS_INT_REMOTE_MODE(0xffff)); +} + +static void rkx110_pcs_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + val = pcs_id ? SER_IRQ_PCS1_DIS : SER_IRQ_PCS0_DIS; + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, PCS_REG30(pcs_id), PCS_INT_STARTUP(0)); + serdes->i2c_write_reg(client, PCS_REG34(pcs_id), PCS_INT_REMOTE_MODE(0)); +} + +static void rkx110_pcs_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, PCS_REG24(pcs_id), &value); + dev_info(serdes->dev, "ser pcs%d startup fatal status:0x%08x\n", pcs_id, value); + + serdes->i2c_read_reg(client, PCS_REG28(pcs_id), &value); + dev_info(serdes->dev, "ser pcs%d remote mode fatal status:0x%08x\n", pcs_id, value); + + /* clear startup fatal status */ + serdes->i2c_write_reg(client, PCS_REG1C(pcs_id), 0xffffffff); + serdes->i2c_write_reg(client, PCS_REG1C(pcs_id), 0xffff0000); + + /* clear remote fatal status */ + serdes->i2c_write_reg(client, PCS_REG14(pcs_id), 0xffffffff); + serdes->i2c_write_reg(client, PCS_REG14(pcs_id), 0xffff0000); +} + +static void rkx110_pma_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + val = pcs_id ? SER_IRQ_PMA_ADAPT1_EN : SER_IRQ_PMA_ADAPT0_EN; + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, SER_PMA_IRQ_EN(pcs_id), FORCE_INITIAL_IRQ_EN | + RTERM_ONCE_TIMEOUT_IRQ_EN | PLL_LOCK_TIMEOUT_IRQ_EN); +} + +static void rkx110_pma_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + val = pcs_id ? SER_IRQ_PMA_ADAPT1_DIS : SER_IRQ_PMA_ADAPT0_DIS; + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, SER_PMA_IRQ_EN(pcs_id), 0); +} + +static void rkx110_pma_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, SER_PMA_IRQ_STATUS(pcs_id), &value); + dev_info(serdes->dev, "ser pma%d irq status:0x%08x\n", pcs_id, value); + + if (value & FORCE_INITIAL_PULSE_STATUS) + dev_info(serdes->dev, "ser pma trig force initial pulse status\n"); + else if (value & RTERM_ONCE_TIMEOUT_STATUS) + dev_info(serdes->dev, "ser pma trig rterm once timeout status\n"); + else if (value & PLL_LOCK_TIMEOUT_STATUS) + dev_info(serdes->dev, "ser pma trig pll lock timeout status\n"); + + /* clear pma irq status */ + serdes->i2c_write_reg(client, SER_PMA_IRQ_STATUS(pcs_id), value); +} + +static void rkx110_remote_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + if (serdes->stream_type == STREAM_DISPLAY) { + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_REMOTE_EN); + rkx120_irq_enable(serdes, DEVICE_REMOTE0); + } +} + + +static void rkx110_remote_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + if (serdes->stream_type == STREAM_DISPLAY) { + serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_REMOTE_DIS); + rkx120_irq_disable(serdes, DEVICE_REMOTE0); + } +} + +static void rkx110_remote_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + if (serdes->stream_type == STREAM_DISPLAY) + rkx120_irq_handler(serdes, DEVICE_REMOTE0); +} + +void rkx110_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + /* enable pcs irq */ + rkx110_pcs_irq_enable(serdes, 0, dev_id); + + /* enable dsirx irq */ + + /* enable gpio irq */ + + /* enable csihost irq */ + + /* enable pma_adapt irq */ + rkx110_pma_irq_enable(serdes, 0, dev_id); + + /* enable efuse irq */ + + /* enable vicap irq */ + + /* enable remote irq */ + rkx110_remote_irq_enable(serdes, dev_id); + + /* enable ext irq */ + + /* enable link irq */ + rkx110_linktx_irq_enable(serdes, dev_id); +} + +void rkx110_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + /* disable pcs irq */ + rkx110_pcs_irq_disable(serdes, 0, dev_id); + + /* disable dsirx irq */ + + /* disable gpio irq */ + + /* disable csihost irq */ + + /* disable pma_adapt irq */ + rkx110_pma_irq_disable(serdes, 0, dev_id); + + /* disable efuse irq */ + + /* disable vicap irq */ + + /* disable remote irq and other lane irq*/ + rkx110_remote_irq_disable(serdes, dev_id); + + /* disable ext irq */ + + /* disable link irq */ + rkx110_linktx_irq_disable(serdes, dev_id); +} + +int rkx110_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 status, mask; + u32 i = 0; + + serdes->i2c_read_reg(client, SER_GRF_IRQ_EN, &mask); + serdes->i2c_read_reg(client, SER_GRF_IRQ_STATUS, &status); + dev_info(serdes->dev, "dev%d get the ser irq status:0x%08x\n", dev_id, status); + + status &= mask; + + while (status) { + switch (status & BIT(i)) { + case SER_IRQ_PCS0: + rkx110_pcs_irq_handler(serdes, 0, dev_id); + break; + case SER_IRQ_PCS1: + rkx110_pcs_irq_handler(serdes, 1, dev_id); + break; + case SER_IRQ_DSIRX0: + /* TBD */ + break; + case SER_IRQ_DSIRX1: + /* TBD */ + break; + case SER_IRQ_GPIO0: + /* TBD */ + break; + case SER_IRQ_GPIO1: + /* TBD */ + break; + case SER_IRQ_CSIHOST0: + /* TBD */ + break; + case SER_IRQ_CSIHOST1: + /* TBD */ + break; + case SER_IRQ_PMA_ADAPT0: + rkx110_pma_irq_handler(serdes, 0, dev_id); + break; + case SER_IRQ_PMA_ADAPT1: + rkx110_pma_irq_handler(serdes, 1, dev_id); + break; + case SER_IRQ_EFUSE: + /* TBD */ + break; + case SER_IRQ_VICAP: + /* TBD */ + break; + case SER_IRQ_REMOTE: + rkx110_remote_irq_handler(serdes, dev_id); + break; + case SER_IRQ_EXT: + /* TBD */ + break; + case SER_IRQ_LINK: + rkx110_linktx_irq_handler(serdes, dev_id); + break; + case SER_IRQ_OTHER_LANE: + /* TBD */ + break; + default: + break; + } + status &= ~BIT(i); + i++; + } + + return 0; +} diff --git a/drivers/mfd/rkx110_x120/rkx110_reg.h b/drivers/mfd/rkx110_x120/rkx110_reg.h index 4d6db3d3c326..d9e18ec944e0 100644 --- a/drivers/mfd/rkx110_x120/rkx110_reg.h +++ b/drivers/mfd/rkx110_x120/rkx110_reg.h @@ -357,6 +357,8 @@ enum { #define SER_GRF_SOC_CON5 GRF_REG(0x114) #define SER_GRF_SOC_CON6 GRF_REG(0x118) #define SER_GRF_SOC_CON7 GRF_REG(0x11C) +#define SER_GRF_IRQ_EN GRF_REG(0x140) +#define SER_GRF_IRQ_STATUS GRF_REG(0x150) #define SER_GRF_SOC_STATUS0 GRF_REG(0x160) enum { @@ -467,6 +469,71 @@ enum { PMA0_DISABLE = HIWORD_UPDATE(0, BIT(8), 8), /* SER_GRF_IRQ_EN */ + SER_IRQ_OTHER_LANE_EN = HIWORD_UPDATE(1, BIT(15), 15), + SER_IRQ_OTHER_LANE_DIS = HIWORD_UPDATE(0, BIT(15), 15), + + SER_IRQ_LINK_EN = HIWORD_UPDATE(1, BIT(14), 14), + SER_IRQ_LINK_DIS = HIWORD_UPDATE(0, BIT(14), 14), + + SER_IRQ_EXT_EN = HIWORD_UPDATE(1, BIT(13), 13), + SER_IRQ_EXT_DIS = HIWORD_UPDATE(0, BIT(13), 13), + + SER_IRQ_REMOTE_EN = HIWORD_UPDATE(1, BIT(12), 12), + SER_IRQ_REMOTE_DIS = HIWORD_UPDATE(0, BIT(12), 12), + + SER_IRQ_VICAP_EN = HIWORD_UPDATE(1, BIT(11), 11), + SER_IRQ_VICAP_DIS = HIWORD_UPDATE(0, BIT(11), 11), + + SER_IRQ_EFUSE_EN = HIWORD_UPDATE(1, BIT(10), 10), + SER_IRQ_EFUSE_DIS = HIWORD_UPDATE(0, BIT(10), 10), + + SER_IRQ_PMA_ADAPT1_EN = HIWORD_UPDATE(1, BIT(9), 9), + SER_IRQ_PMA_ADAPT1_DIS = HIWORD_UPDATE(0, BIT(9), 9), + + SER_IRQ_PMA_ADAPT0_EN = HIWORD_UPDATE(1, BIT(8), 8), + SER_IRQ_PMA_ADAPT0_DIS = HIWORD_UPDATE(0, BIT(8), 8), + + SER_IRQ_CSIHOST1_EN = HIWORD_UPDATE(1, BIT(7), 7), + SER_IRQ_CSIHOST1_DIS = HIWORD_UPDATE(0, BIT(7), 7), + + SER_IRQ_CSIHOST0_EN = HIWORD_UPDATE(1, BIT(6), 6), + SER_IRQ_CSIHOST0_DIS = HIWORD_UPDATE(0, BIT(6), 6), + + SER_IRQ_GPIO1_EN = HIWORD_UPDATE(1, BIT(5), 5), + SER_IRQ_GPIO1_DIS = HIWORD_UPDATE(0, BIT(5), 5), + + SER_IRQ_GPIO0_EN = HIWORD_UPDATE(1, BIT(4), 4), + SER_IRQ_GPIO0_DIS = HIWORD_UPDATE(0, BIT(4), 4), + + SER_IRQ_DSIRX1_EN = HIWORD_UPDATE(1, BIT(3), 3), + SER_IRQ_DSIRX1_DIS = HIWORD_UPDATE(0, BIT(3), 3), + + SER_IRQ_DSIRX0_EN = HIWORD_UPDATE(1, BIT(2), 2), + SER_IRQ_DSIRX0_DIS = HIWORD_UPDATE(0, BIT(2), 2), + + SER_IRQ_PCS1_EN = HIWORD_UPDATE(1, BIT(1), 1), + SER_IRQ_PCS1_DIS = HIWORD_UPDATE(0, BIT(1), 1), + + SER_IRQ_PCS0_EN = HIWORD_UPDATE(1, BIT(0), 0), + SER_IRQ_PCS0_DIS = HIWORD_UPDATE(0, BIT(0), 0), + + /* SER_GRF_IRQ_STATUS */ + SER_IRQ_OTHER_LANE = BIT(15), + SER_IRQ_LINK = BIT(14), + SER_IRQ_EXT = BIT(13), + SER_IRQ_REMOTE = BIT(12), + SER_IRQ_VICAP = BIT(11), + SER_IRQ_EFUSE = BIT(10), + SER_IRQ_PMA_ADAPT1 = BIT(9), + SER_IRQ_PMA_ADAPT0 = BIT(8), + SER_IRQ_CSIHOST1 = BIT(7), + SER_IRQ_CSIHOST0 = BIT(6), + SER_IRQ_GPIO1 = BIT(5), + SER_IRQ_GPIO0 = BIT(4), + SER_IRQ_DSIRX1 = BIT(3), + SER_IRQ_DSIRX0 = BIT(2), + SER_IRQ_PCS1 = BIT(1), + SER_IRQ_PCS0 = BIT(0), /* SER_GRF_SOC_STATUS0 */ SER_PCS1_READY = BIT(21), diff --git a/drivers/mfd/rkx110_x120/rkx110_x120.h b/drivers/mfd/rkx110_x120/rkx110_x120.h index 545cb5b6f044..67e544fb7b47 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120.h +++ b/drivers/mfd/rkx110_x120/rkx110_x120.h @@ -262,7 +262,9 @@ struct rk_serdes { struct regulator *supply; struct gpio_desc *reset; struct gpio_desc *enable; + struct gpio_desc *irq_gpio; + int irq; /* * Control by I2C-Debug */ @@ -364,4 +366,10 @@ void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 bool is_rx); void rkx120_linkrx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 func_id, bool is_rx); +void rkx110_irq_enable(struct rk_serdes *serdes, u8 dev_id); +void rkx110_irq_disable(struct rk_serdes *serdes, u8 dev_id); +int rkx110_irq_handler(struct rk_serdes *serdes, u8 dev_id); +void rkx120_irq_enable(struct rk_serdes *serdes, u8 dev_id); +void rkx120_irq_disable(struct rk_serdes *serdes, u8 dev_id); +int rkx120_irq_handler(struct rk_serdes *serdes, u8 dev_id); #endif diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_core.c b/drivers/mfd/rkx110_x120/rkx110_x120_core.c index 5087ae472a91..dd23e952d739 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120_core.c +++ b/drivers/mfd/rkx110_x120/rkx110_x120_core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -652,6 +653,25 @@ static int rk_serdes_passthrough_init(struct rk_serdes *serdes) kfree(configs); } + /* config irq passthrough */ + if (serdes->stream_type == STREAM_DISPLAY) { + rkx110_linktx_passthrough_cfg(serdes, DEVICE_LOCAL, RK_SERDES_PASSTHROUGH_IRQ, + false); + rkx120_linkrx_passthrough_cfg(serdes, DEVICE_REMOTE0, RK_SERDES_PASSTHROUGH_IRQ, + true); + if (serdes->remote_nr == 2) + rkx120_linkrx_passthrough_cfg(serdes, DEVICE_REMOTE1, + RK_SERDES_PASSTHROUGH_IRQ, true); + } else { + rkx120_linkrx_passthrough_cfg(serdes, DEVICE_LOCAL, RK_SERDES_PASSTHROUGH_IRQ, + false); + rkx110_linktx_passthrough_cfg(serdes, DEVICE_REMOTE0, RK_SERDES_PASSTHROUGH_IRQ, + true); + if (serdes->remote_nr == 2) + rkx110_linktx_passthrough_cfg(serdes, DEVICE_REMOTE1, + RK_SERDES_PASSTHROUGH_IRQ, true); + } + return 0; } @@ -953,9 +973,66 @@ static int rk_serdes_pinctrl_init(struct rk_serdes *serdes) kfree(configs); } + /* config irq pinctrl */ + if (serdes->stream_type == STREAM_DISPLAY) { + serdes->set_hwpin(serdes, serdes->chip[DEVICE_LOCAL].client, PIN_RKX110, + RK_SERDES_SER_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC2); + serdes->set_hwpin(serdes, serdes->chip[DEVICE_REMOTE0].client, PIN_RKX120, + RK_SERDES_DES_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC0); + if (serdes->remote_nr == 2) + serdes->set_hwpin(serdes, serdes->chip[DEVICE_REMOTE1].client, PIN_RKX120, + RK_SERDES_DES_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC0); + } else { + serdes->set_hwpin(serdes, serdes->chip[DEVICE_REMOTE0].client, PIN_RKX110, + RK_SERDES_SER_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC0); + serdes->set_hwpin(serdes, serdes->chip[DEVICE_LOCAL].client, PIN_RKX120, + RK_SERDES_DES_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC2); + if (serdes->remote_nr == 2) + serdes->set_hwpin(serdes, serdes->chip[DEVICE_REMOTE1].client, PIN_RKX110, + RK_SERDES_SER_GPIO_BANK0, RK_SERDES_GPIO_PIN_A4, + RK_SERDES_PIN_CONFIG_MUX_FUNC2); + } + return 0; } +static int rk_serdes_irq_enable(struct rk_serdes *serdes) +{ + if (serdes->stream_type == STREAM_DISPLAY) + rkx110_irq_enable(serdes, DEVICE_LOCAL); + else + rkx120_irq_enable(serdes, DEVICE_LOCAL); + + return 0; +} + +__maybe_unused static int rk_serdes_irq_disable(struct rk_serdes *serdes) +{ + if (serdes->stream_type == STREAM_DISPLAY) + rkx110_irq_disable(serdes, DEVICE_LOCAL); + else + rkx120_irq_disable(serdes, DEVICE_LOCAL); + + return 0; +} + +static irqreturn_t rk_serdes_irq_handler(int irq, void *arg) +{ + struct rk_serdes *serdes = arg; + + if (serdes->stream_type == STREAM_DISPLAY) + rkx110_irq_handler(serdes, DEVICE_LOCAL); + else + rkx120_irq_handler(serdes, DEVICE_LOCAL); + + return IRQ_HANDLED; +} + static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; @@ -1014,6 +1091,30 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic return ret; } + serdes->irq_gpio = devm_gpiod_get_optional(dev, "irq", GPIOD_IN); + if (IS_ERR(serdes->irq_gpio)) { + ret = PTR_ERR(serdes->irq_gpio); + dev_err(dev, "failed to request irq GPIO: %d\n", ret); + return ret; + } + if (serdes->irq_gpio) { + serdes->irq = gpiod_to_irq(serdes->irq_gpio); + if (serdes->irq < 0) + return dev_err_probe(dev, serdes->irq, "failed to get irq\n"); + + irq_set_status_flags(serdes->irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(dev, serdes->irq, NULL, + rk_serdes_irq_handler, + IRQF_TRIGGER_LOW | + IRQF_ONESHOT, "serdes-irq", serdes); + if (ret) { + dev_err(dev, "failed to request serdes interrupt\n"); + return ret; + } + } else { + dev_warn(dev, "no support serdes irq function\n"); + } + disp_np = of_get_child_by_name(dev->of_node, "serdes-panel"); if (disp_np) { serdes->stream_type = STREAM_DISPLAY; @@ -1062,6 +1163,9 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic rk_serdes_set_rate(serdes, RATE_4GBPS_83M); rk_serdes_pinctrl_init(serdes); rk_serdes_passthrough_init(serdes); + rk_serdes_irq_enable(serdes); + enable_irq(serdes->irq); + out: rk_serdes_debugfs_init(serdes); diff --git a/drivers/mfd/rkx110_x120/rkx120_linkrx.c b/drivers/mfd/rkx110_x120/rkx120_linkrx.c index bae51fdb0cc6..f4a80a89fd75 100644 --- a/drivers/mfd/rkx110_x120/rkx120_linkrx.c +++ b/drivers/mfd/rkx110_x120/rkx120_linkrx.c @@ -36,6 +36,8 @@ #define LANE0_DATA_WIDTH_16BIT UPDATE(1, 13, 12) #define LANE0_DATA_WIDTH_24BIT UPDATE(2, 13, 12) #define LANE0_DATA_WIDTH_32BIT UPDATE(3, 13, 12) + #define LANE1_PKT_LOSE_NUM_CLR BIT(9) + #define LANE0_PKT_LOSE_NUM_CLR BIT(8) #define LANE0_EN BIT(4) #define LANE1_EN BIT(5) #define DES_EN BIT(0) @@ -115,6 +117,42 @@ #define E2_FIRST_FRAME_DEL BIT(6) #define E1_FIRST_FRAME_DEL BIT(5) #define E0_FIRST_FRAME_DEL BIT(4) +#define RKLINK_DES_FIFO_STATUS LINK_REG(0x0084) + #define AUDIO_FIFO_UNDERRUN BIT(29) + #define AUDIO_ORDER_UNDERRUN BIT(28) + #define VIDEO_DATA_FIFO_UNDERRUN BIT(27) + #define VIDEO_ORDER_UNDERRUN BIT(26) + #define CMD_FIFO_UNDERRUN BIT(25) + #define E1_ORDER_MIS BIT(15) + #define E0_ORDER_MIS BIT(14) + #define AUDIO_FIFO_OVERFLOW BIT(13) + #define AUDIO_ORDER_OVERFLOW BIT(12) + #define VIDEO_DATA_FIFO_OVERFLOW GENMASK(11, 8) + #define VIDEO_ORDER_OVERFLOW GENMASK(7, 4) + #define CMD_FIFO_OVERFLOW GENMASK(3, 0) +#define RKLINK_DES_SINK_IRQ_EN LINK_REG(0x0088) + #define COMP_NOT_ENOUGH_IRQ_FLAG BIT(26) + #define VIDEO_FM_IRQ_FLAG BIT(25) + #define AUDIO_FM_IRQ_FLAG BIT(24) + #define ORDER_MIS_IRQ_FLAG BIT(23) + #define FIFO_UNDERRUN_IRQ_FLAG BIT(22) + #define FIFO_OVERFLOW_IRQ_FLAG BIT(21) + #define PKT_LOSE_IRQ_FLAG BIT(20) + #define LAST_ERROR_IRQ_FLAG BIT(19) + #define ECC2BIT_ERROR_IRQ_FLAG BIT(18) + #define ECC1BIT_ERROR_IRQ_FLAG BIT(17) + #define CRC_ERROR_IRQ_FLAG BIT(16) + #define COMP_NOT_ENOUGH_IRQ_OUTPUT_EN BIT(10) + #define VIDEO_FM_IRQ_OUTPUT_EN BIT(9) + #define AUDIO_FM_IRQ_OUTPUT_EN BIT(8) + #define ORDER_MIS_IRQ_OUTPUT_EN BIT(7) + #define FIFO_UNDERRUN_IRQ_OUTPUT_EN BIT(6) + #define FIFO_OVERFLOW_IRQ_OUTPUT_EN BIT(5) + #define PKT_LOSE_IRQ_OUTPUT_EN BIT(4) + #define LAST_ERROR_IRQ_OUTPUT_EN BIT(3) + #define ECC2BIT_ERROR_IRQ_OUTPUT_EN BIT(2) + #define ECC1BIT_ERROR_IRQ_OUTPUT_EN BIT(1) + #define CRC_ERROR_IRQ_OUTPUT_EN BIT(0) #define DES_RKLINK_STOP_CFG LINK_REG(0x009C) #define STOP_AUDIO BIT(4) @@ -147,6 +185,7 @@ #define PCS_REG24(id) PCS_REG(id, 0x24) #define PCS_REG28(id) PCS_REG(id, 0x28) #define PCS_REG30(id) PCS_REG(id, 0x30) + #define DES_PCS_INI_EN(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0) #define PCS_REG34(id) PCS_REG(id, 0x34) #define PCS_REG40(id) PCS_REG(id, 0x40) @@ -226,6 +265,19 @@ #define DES_PMA_LOAD0E(id) PMA_REG(id, 0x48) #define DES_PMA_REG100(id) PMA_REG(id, 0x100) +#define DES_PMA_IRQ_EN(id) PMA_REG(id, 0xF0) + #define FORCE_INITIAL_IRQ_EN HIWORD_UPDATE(1, BIT(6), 6) + #define RX_RDY_NEG_IRQ_EN HIWORD_UPDATE(1, BIT(5), 5) + #define RX_LOS_IRQ_EN HIWORD_UPDATE(1, BIT(4), 4) + #define RX_RDY_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(2), 2) + #define PLL_LOCK_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(0), 0) +#define DES_PMA_IRQ_STATUS(id) PMA_REG(id, 0xF4) + #define FORCE_INITIAL_IRQ_STATUS BIT(6) + #define RX_RDY_NEG_IRQ_STATUS BIT(5) + #define RX_LOS_IRQ_STATUS BIT(4) + #define RX_RDY_TIMEOUT_IRQ_STATUS BIT(2) + #define PLL_LOCK_TIMEOUT_IRQ_STATUS BIT(0) + static const struct rk_serdes_pt des_pt[] = { { /* gpi_gpo_0 */ @@ -813,3 +865,354 @@ void rkx120_des_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 serdes->i2c_update_bits(client, DES_GRF_SOC_CON4, mask, val); } + + +static void rkx120_linkrx_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, DES_IRQ_LINK_EN); + + serdes->i2c_write_reg(client, RKLINK_DES_SINK_IRQ_EN, FIFO_UNDERRUN_IRQ_OUTPUT_EN | + FIFO_OVERFLOW_IRQ_OUTPUT_EN); +} + +static void rkx120_linkrx_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, DES_IRQ_LINK_DIS); + + serdes->i2c_read_reg(client, RKLINK_DES_SINK_IRQ_EN, &val); + val &= ~(FIFO_UNDERRUN_IRQ_OUTPUT_EN | FIFO_OVERFLOW_IRQ_OUTPUT_EN); + serdes->i2c_write_reg(client, RKLINK_DES_SINK_IRQ_EN, val); +} + +static void rkx120_linkrx_fifo_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, RKLINK_DES_FIFO_STATUS, &value); + dev_err(serdes->dev, "des rklink fifo status:0x%x\n", value); + + if (value & AUDIO_FIFO_UNDERRUN) + dev_err(serdes->dev, "linkrx audio fifo underrun\n"); + if (value & AUDIO_ORDER_UNDERRUN) + dev_err(serdes->dev, "linkrx audio order underrun\n"); + if (value & VIDEO_DATA_FIFO_UNDERRUN) + dev_err(serdes->dev, "linkrx video data fifo underrun\n"); + if (value & VIDEO_ORDER_UNDERRUN) + dev_err(serdes->dev, "linkrx video order underrun\n"); + if (value & CMD_FIFO_UNDERRUN) + dev_err(serdes->dev, "linkrx cmd fifo underrun\n"); + if (value & E1_ORDER_MIS) + dev_err(serdes->dev, "linkrx e1 order miss\n"); + if (value & E0_ORDER_MIS) + dev_err(serdes->dev, "linkrx e0 order miss\n"); + if (value & AUDIO_FIFO_OVERFLOW) + dev_err(serdes->dev, "linkrx audio fifo overflow\n"); + if (value & AUDIO_ORDER_OVERFLOW) + dev_err(serdes->dev, "linkrx audio order overflow\n"); + if (value & VIDEO_DATA_FIFO_OVERFLOW) + dev_err(serdes->dev, "linkrx video data fifo overflow\n"); + if (value & VIDEO_ORDER_OVERFLOW) + dev_err(serdes->dev, "linkrx video order overflow\n"); + if (value & CMD_FIFO_OVERFLOW) + dev_err(serdes->dev, "linkrx cmd fifo overflow\n"); + + serdes->i2c_write_reg(client, RKLINK_DES_FIFO_STATUS, value); +} + +static void rkx120_linkrx_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 flag, value; + int i = 0; + + serdes->i2c_read_reg(client, RKLINK_DES_SINK_IRQ_EN, &flag); + flag &= COMP_NOT_ENOUGH_IRQ_FLAG | VIDEO_FM_IRQ_FLAG | AUDIO_FM_IRQ_FLAG | + ORDER_MIS_IRQ_FLAG | FIFO_UNDERRUN_IRQ_FLAG | FIFO_OVERFLOW_IRQ_FLAG | + PKT_LOSE_IRQ_FLAG | LAST_ERROR_IRQ_FLAG | ECC2BIT_ERROR_IRQ_FLAG | + ECC1BIT_ERROR_IRQ_FLAG | CRC_ERROR_IRQ_FLAG; + dev_info(serdes->dev, "linkrx irq flag:0x%08x\n", flag); + while (flag) { + switch (flag & BIT(i)) { + case COMP_NOT_ENOUGH_IRQ_FLAG: + break; + case VIDEO_FM_IRQ_FLAG: + break; + case AUDIO_FM_IRQ_FLAG: + break; + case ORDER_MIS_IRQ_FLAG: + case FIFO_UNDERRUN_IRQ_FLAG: + case FIFO_OVERFLOW_IRQ_FLAG: + flag &= ~(ORDER_MIS_IRQ_FLAG | FIFO_UNDERRUN_IRQ_FLAG | + FIFO_OVERFLOW_IRQ_FLAG); + rkx120_linkrx_fifo_handler(serdes, dev_id); + break; + case PKT_LOSE_IRQ_FLAG: + /* clear pkt lost irq flag */ + serdes->i2c_read_reg(client, RKLINK_DES_LANE_ENGINE_CFG, &value); + value |= LANE0_PKT_LOSE_NUM_CLR | LANE1_PKT_LOSE_NUM_CLR; + serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, value); + break; + case LAST_ERROR_IRQ_FLAG: + case ECC2BIT_ERROR_IRQ_FLAG: + case ECC1BIT_ERROR_IRQ_FLAG: + case CRC_ERROR_IRQ_FLAG: + flag &= ~(LAST_ERROR_IRQ_FLAG | ECC2BIT_ERROR_IRQ_FLAG | + ECC1BIT_ERROR_IRQ_FLAG | CRC_ERROR_IRQ_FLAG); + serdes->i2c_read_reg(client, RKLINK_DES_SINK_IRQ_EN, &value); + dev_info(serdes->dev, "linkrx ecc crc result:0x%08x\n", value); + /* clear ecc crc irq flag */ + serdes->i2c_write_reg(client, RKLINK_DES_SINK_IRQ_EN, value); + break; + default: + break; + } + flag &= ~BIT(i); + i++; + } +} +static void rkx120_pcs_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + val = pcs_id ? DES_IRQ_PCS1_EN : DES_IRQ_PCS0_EN; + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, PCS_REG30(pcs_id), DES_PCS_INI_EN(0xffff)); +} + +static void rkx120_pcs_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + val = pcs_id ? DES_IRQ_PCS1_DIS : DES_IRQ_PCS0_DIS; + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, PCS_REG30(pcs_id), DES_PCS_INI_EN(0)); +} + +static void rkx120_pcs_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, PCS_REG20(pcs_id), &value); + dev_info(serdes->dev, "des pcs%d fatal status:0x%08x\n", pcs_id, value); + + /* clear fatal status */ + serdes->i2c_write_reg(client, PCS_REG10(pcs_id), 0xffffffff); + serdes->i2c_write_reg(client, PCS_REG10(pcs_id), 0xffff0000); +} + +static void rkx120_pma_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + val = pcs_id ? DES_IRQ_PMA_ADAPT1_EN : DES_IRQ_PMA_ADAPT0_EN; + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, DES_PMA_IRQ_EN(pcs_id), FORCE_INITIAL_IRQ_EN | + RX_RDY_NEG_IRQ_EN | RX_LOS_IRQ_EN | RX_RDY_TIMEOUT_IRQ_EN | + PLL_LOCK_TIMEOUT_IRQ_EN); +} + +static void rkx120_pma_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + val = pcs_id ? DES_IRQ_PMA_ADAPT1_DIS : DES_IRQ_PMA_ADAPT0_DIS; + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, val); + + serdes->i2c_write_reg(client, DES_PMA_IRQ_EN(pcs_id), 0); +} + +static void rkx120_pma_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 value; + + serdes->i2c_read_reg(client, DES_PMA_IRQ_STATUS(pcs_id), &value); + dev_info(serdes->dev, "des pma%d irq status:0x%08x\n", pcs_id, value); + + if (value & FORCE_INITIAL_IRQ_STATUS) + dev_info(serdes->dev, "des pma trig force initial pulse status\n"); + else if (value & RX_RDY_NEG_IRQ_STATUS) + dev_info(serdes->dev, "des pma trig rx rdy neg status\n"); + else if (value & RX_LOS_IRQ_STATUS) + dev_info(serdes->dev, "des pma trig rx los status\n"); + else if (value & RX_RDY_TIMEOUT_IRQ_STATUS) + dev_info(serdes->dev, "des pma trig rx rdy timeout status\n"); + else if (value & PLL_LOCK_TIMEOUT_IRQ_STATUS) + dev_info(serdes->dev, "des pma trig pll lock timeout status\n"); + + /* clear pma irq status */ + serdes->i2c_write_reg(client, DES_PMA_IRQ_STATUS(pcs_id), value); +} + +static void rkx120_remote_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + if (serdes->stream_type == STREAM_CAMERA) { + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, DES_IRQ_REMOTE_EN); + rkx110_irq_enable(serdes, DEVICE_REMOTE0); + } +} + +static void rkx120_remote_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + if (serdes->stream_type == STREAM_CAMERA) { + serdes->i2c_write_reg(client, DES_GRF_IRQ_EN, DES_IRQ_REMOTE_DIS); + rkx110_irq_disable(serdes, DEVICE_REMOTE0); + } +} + +static void rkx120_remote_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + if (serdes->stream_type == STREAM_CAMERA) + rkx110_irq_handler(serdes, DEVICE_REMOTE0); +} + +void rkx120_irq_enable(struct rk_serdes *serdes, u8 dev_id) +{ + /* enable pcs irq */ + rkx120_pcs_irq_enable(serdes, 0, dev_id); + + /* enable efuse irq */ + + /* enable gpio irq */ + + /* enable csitx irq */ + + /* enable mipi dsi host irq */ + + /* enable pma adapt irq */ + rkx120_pma_irq_enable(serdes, 0, dev_id); + + /* enable remote irq and other lane irq */ + rkx120_remote_irq_enable(serdes, dev_id); + + /* enable pwm irq */ + + /* enable dvp tx irq */ + + /* enable link irq */ + rkx120_linkrx_irq_enable(serdes, dev_id); + + /* enable ext irq */ + + /* enable ext irq */ +} + +void rkx120_irq_disable(struct rk_serdes *serdes, u8 dev_id) +{ + /* disable pcs irq */ + rkx120_pcs_irq_disable(serdes, 0, dev_id); + + /* disable efuse irq */ + + /* disable gpio irq */ + + /* disable csitx irq */ + + /* disable mipi dsi host irq */ + + /* disable pma adapt irq */ + rkx120_pma_irq_disable(serdes, 0, dev_id); + + /* disable remote irq */ + rkx120_remote_irq_disable(serdes, dev_id); + + /* disable pwm irq */ + + /* disable dvp tx irq */ + + /* disable link irq */ + rkx120_linkrx_irq_disable(serdes, dev_id); + + /* disable ext irq */ +} + +int rkx120_irq_handler(struct rk_serdes *serdes, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 status = 0; + u32 mask = 0; + u32 i = 0; + + serdes->i2c_read_reg(client, DES_GRF_IRQ_EN, &mask); + serdes->i2c_read_reg(client, DES_GRF_IRQ_STATUS, &status); + dev_info(serdes->dev, "dev%d get the des irq status:0x%08x\n", dev_id, status); + status &= mask; + + while (status) { + switch (status & BIT(i)) { + case DES_IRQ_PCS0: + rkx120_pcs_irq_handler(serdes, 0, dev_id); + break; + case DES_IRQ_PCS1: + rkx120_pcs_irq_handler(serdes, 1, dev_id); + break; + case DES_IRQ_EFUSE: + /* TBD */ + break; + case DES_IRQ_GPIO0: + /* TBD */ + break; + case DES_IRQ_GPIO1: + /* TBD */ + break; + case DES_IRQ_CSITX0: + /* TBD */ + break; + case DES_IRQ_CSITX1: + /* TBD */ + break; + case DES_IRQ_MIPI_DSI_HOST: + /* TBD */ + break; + case DES_IRQ_PMA_ADAPT0: + rkx120_pma_irq_handler(serdes, 0, dev_id); + break; + case DES_IRQ_PMA_ADAPT1: + rkx120_pma_irq_handler(serdes, 1, dev_id); + break; + case DES_IRQ_REMOTE: + rkx120_remote_irq_handler(serdes, dev_id); + break; + case DES_IRQ_PWM: + /* TBD */ + break; + case DES_IRQ_DVP_TX: + /* TBD */ + break; + case DES_IRQ_LINK: + rkx120_linkrx_irq_handler(serdes, dev_id); + break; + case DES_IRQ_EXT: + /* TBD */ + break; + case DES_IRQ_OTHER_LANE: + /* TBD */ + break; + default: + break; + } + status &= ~BIT(i); + i++; + } + + return 0; +} + diff --git a/drivers/mfd/rkx110_x120/rkx120_reg.h b/drivers/mfd/rkx110_x120/rkx120_reg.h index 91e7c913e29d..9640ae21c17a 100644 --- a/drivers/mfd/rkx110_x120/rkx120_reg.h +++ b/drivers/mfd/rkx110_x120/rkx120_reg.h @@ -328,6 +328,8 @@ enum { #define DES_GRF_SOC_CON5 GRF_REG(0x114) #define DES_GRF_SOC_CON6 GRF_REG(0x118) #define DES_GRF_SOC_CON7 GRF_REG(0x11C) +#define DES_GRF_IRQ_EN GRF_REG(0x140) +#define DES_GRF_IRQ_STATUS GRF_REG(0x150) enum { /* SOC_CON0 */ @@ -433,6 +435,71 @@ enum { /* SOC_CON9 */ /* DES_GRF_IRQ_EN */ + DES_IRQ_OTHER_LANE_EN = HIWORD_UPDATE(1, BIT(15), 15), + DES_IRQ_OTHER_LANE_DIS = HIWORD_UPDATE(0, BIT(15), 15), + + DES_IRQ_EXT_EN = HIWORD_UPDATE(1, BIT(14), 14), + DES_IRQ_EXT_DIS = HIWORD_UPDATE(0, BIT(14), 14), + + DES_IRQ_LINK_EN = HIWORD_UPDATE(1, BIT(13), 13), + DES_IRQ_LINK_DIS = HIWORD_UPDATE(0, BIT(13), 13), + + DES_IRQ_DVP_TX_EN = HIWORD_UPDATE(1, BIT(12), 12), + DES_IRQ_DVP_TX_DIS = HIWORD_UPDATE(0, BIT(12), 12), + + DES_IRQ_PWM_EN = HIWORD_UPDATE(1, BIT(11), 11), + DES_IRQ_PWM_DIS = HIWORD_UPDATE(0, BIT(11), 11), + + DES_IRQ_REMOTE_EN = HIWORD_UPDATE(1, BIT(10), 10), + DES_IRQ_REMOTE_DIS = HIWORD_UPDATE(0, BIT(10), 10), + + DES_IRQ_PMA_ADAPT1_EN = HIWORD_UPDATE(1, BIT(9), 9), + DES_IRQ_PMA_ADAPT1_DIS = HIWORD_UPDATE(0, BIT(9), 9), + + DES_IRQ_PMA_ADAPT0_EN = HIWORD_UPDATE(1, BIT(8), 8), + DES_IRQ_PMA_ADAPT0_DIS = HIWORD_UPDATE(0, BIT(8), 8), + + DES_IRQ_MIPI_DSI_HOST_EN = HIWORD_UPDATE(1, BIT(7), 7), + DES_IRQ_MIPI_DSI_HOST_DIS = HIWORD_UPDATE(0, BIT(7), 7), + + DES_IRQ_CSITX1_EN = HIWORD_UPDATE(1, BIT(6), 6), + DES_IRQ_CSITX1_DIS = HIWORD_UPDATE(0, BIT(6), 6), + + DES_IRQ_CSITX0_EN = HIWORD_UPDATE(1, BIT(5), 5), + DES_IRQ_CSITX0_DIS = HIWORD_UPDATE(0, BIT(5), 5), + + DES_IRQ_GPIO1_EN = HIWORD_UPDATE(1, BIT(4), 4), + DES_IRQ_GPIO1_DIS = HIWORD_UPDATE(0, BIT(4), 4), + + DES_IRQ_GPIO0_EN = HIWORD_UPDATE(1, BIT(3), 3), + DES_IRQ_GPIO0_DIS = HIWORD_UPDATE(0, BIT(3), 3), + + DES_IRQ_EFUSE_EN = HIWORD_UPDATE(1, BIT(2), 2), + DES_IRQ_EFUSE_DIS = HIWORD_UPDATE(0, BIT(2), 2), + + DES_IRQ_PCS1_EN = HIWORD_UPDATE(1, BIT(1), 1), + DES_IRQ_PCS1_DIS = HIWORD_UPDATE(0, BIT(1), 1), + + DES_IRQ_PCS0_EN = HIWORD_UPDATE(1, BIT(0), 0), + DES_IRQ_PCS0_DIS = HIWORD_UPDATE(0, BIT(0), 0), + + /* DES_GRF_IRQ_STATUS */ + DES_IRQ_PCS0 = BIT(0), + DES_IRQ_PCS1 = BIT(1), + DES_IRQ_EFUSE = BIT(2), + DES_IRQ_GPIO0 = BIT(3), + DES_IRQ_GPIO1 = BIT(4), + DES_IRQ_CSITX0 = BIT(5), + DES_IRQ_CSITX1 = BIT(6), + DES_IRQ_MIPI_DSI_HOST = BIT(7), + DES_IRQ_PMA_ADAPT0 = BIT(8), + DES_IRQ_PMA_ADAPT1 = BIT(9), + DES_IRQ_REMOTE = BIT(10), + DES_IRQ_PWM = BIT(11), + DES_IRQ_DVP_TX = BIT(12), + DES_IRQ_LINK = BIT(13), + DES_IRQ_EXT = BIT(14), + DES_IRQ_OTHER_LANE = BIT(15), /* DES_GRF_SOC_STATUS0 */ DES_PCS1_READY = BIT(1),