Загрузка данных
static const struct regmap_config fsl_xcvr_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = FSL_XCVR_MAX_REG,
.reg_defaults = fsl_xcvr_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults),
.readable_reg = fsl_xcvr_readable_reg,
.volatile_reg = fsl_xcvr_volatile_reg,
.writeable_reg = fsl_xcvr_writeable_reg,
.cache_type = REGCACHE_FLAT,
};
static const struct reg_default fsl_xcvr_phy_reg_defaults[] = {
{ FSL_XCVR_PHY_CTRL, 0x58200804 },
{ FSL_XCVR_PHY_STATUS, 0x00000000 },
{ FSL_XCVR_PHY_ANALOG_TRIM, 0x00260F13 },
{ FSL_XCVR_PHY_SLEW_RATE_TRIM, 0x00000411 },
{ FSL_XCVR_PHY_DATA_TEST_DELAY, 0x00990000 },
{ FSL_XCVR_PHY_TEST_CTRL, 0x00000000 },
{ FSL_XCVR_PHY_DIFF_CDR_CTRL, 0x016D0009 },
{ FSL_XCVR_PHY_CTRL2, 0x80000000 },
};
static const struct regmap_config fsl_xcvr_regmap_phy_cfg = {
.reg_bits = 8,
.reg_stride = 4,
.val_bits = 32,
.max_register = FSL_XCVR_PHY_CTRL2_TOG,
.reg_defaults = fsl_xcvr_phy_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(fsl_xcvr_phy_reg_defaults),
.cache_type = REGCACHE_FLAT,
.reg_read = fsl_xcvr_phy_reg_read,
.reg_write = fsl_xcvr_phy_reg_write,
};
static const struct regmap_config fsl_xcvr_regmap_pllv0_cfg = {
.reg_bits = 8,
.reg_stride = 4,
.val_bits = 32,
.max_register = FSL_XCVR_PLL_STAT0_TOG,
.cache_type = REGCACHE_FLAT,
.reg_read = fsl_xcvr_pll_reg_read,
.reg_write = fsl_xcvr_pll_reg_write,
};
static const struct regmap_config fsl_xcvr_regmap_pllv1_cfg = {
.reg_bits = 8,
.reg_stride = 4,
.val_bits = 32,
.max_register = FSL_XCVR_GP_PLL_STATUS_TOG,
.cache_type = REGCACHE_FLAT,
.reg_read = fsl_xcvr_pll_reg_read,
.reg_write = fsl_xcvr_pll_reg_write,
};
static void reset_rx_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst);
struct device *dev = &xcvr->pdev->dev;
unsigned long lock_flags;
u32 ext_ctrl;
dev_dbg(dev, "reset rx path\n");
spin_lock_irqsave(&xcvr->lock, lock_flags);
regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl);
if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) {
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_RD_DIS,
FSL_XCVR_EXT_CTRL_DMA_RD_DIS);
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET);
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_RD_DIS,
0);
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
0);
}
spin_unlock_irqrestore(&xcvr->lock, lock_flags);
}
static void edid_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work);
struct device *dev = &xcvr->pdev->dev;
const struct drm_edid *edid;
dev_dbg(dev, "trigger edid read\n");
if (xcvr->bridge) {
edid = drm_bridge_edid_read(xcvr->bridge, NULL);
drm_edid_free(edid);
}
}
static irqreturn_t irq0_isr(int irq, void *devid)
{
struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
struct device *dev = &xcvr->pdev->dev;
struct regmap *regmap = xcvr->regmap;
void __iomem *reg_ctrl, *reg_buff;
u32 isr, isr_clr = 0, val, i;
regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
if (isr & FSL_XCVR_IRQ_NEW_CS) {
dev_dbg(dev, "Received new CS block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_CS;
if (xcvr->soc_data->fw_name) {
/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(8));
/* Find updated CS buffer */
reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
memcpy_fromio(&val, reg_ctrl, sizeof(val));
if (!val) {
reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
memcpy_fromio(&val, reg_ctrl, sizeof(val));
}
if (val) {
/* copy CS buffer */
memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
sizeof(xcvr->rx_iec958.status));
for (i = 0; i < 6; i++) {
val = *(u32 *)(xcvr->rx_iec958.status + i*4);
*(u32 *)(xcvr->rx_iec958.status + i*4) =
bitrev32(val);
}
/* clear CS control register */
memset_io(reg_ctrl, 0, sizeof(val));
}
} else {
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_0,
(u32 *)&xcvr->rx_iec958.status[0]);
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_1,
(u32 *)&xcvr->rx_iec958.status[4]);
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_2,
(u32 *)&xcvr->rx_iec958.status[8]);
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_3,
(u32 *)&xcvr->rx_iec958.status[12]);
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_4,
(u32 *)&xcvr->rx_iec958.status[16]);
regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_5,
(u32 *)&xcvr->rx_iec958.status[20]);
for (i = 0; i < 6; i++) {
val = *(u32 *)(xcvr->rx_iec958.status + i * 4);
*(u32 *)(xcvr->rx_iec958.status + i * 4) =
bitrev32(val);
}
regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
FSL_XCVR_RX_DPTH_CTRL_CSA);
}
}
if (isr & FSL_XCVR_IRQ_NEW_UD) {
dev_dbg(dev, "Received new UD block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_UD;
}
if (isr & FSL_XCVR_IRQ_MUTE) {
dev_dbg(dev, "HW mute bit detected\n");
isr_clr |= FSL_XCVR_IRQ_MUTE;
}
if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) {
dev_dbg(dev, "RX/TX FIFO full/empty\n");
isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR;
}
if (isr & FSL_XCVR_IRQ_ARC_MODE) {
dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
isr_clr |= FSL_XCVR_IRQ_ARC_MODE;
}
if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) {
dev_dbg(dev, "DMA read request\n");
isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ;
}
if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) {
dev_dbg(dev, "DMA write request\n");
isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
}
if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) {
dev_dbg(dev, "CMDC status update\n");
schedule_work(&xcvr->work);
isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD;
}
if (isr & FSL_XCVR_IRQ_PREAMBLE_MISMATCH) {
dev_dbg(dev, "Preamble mismatch\n");
isr_clr |= FSL_XCVR_IRQ_PREAMBLE_MISMATCH;
}
if (isr & FSL_XCVR_IRQ_UNEXP_PRE_REC) {
dev_dbg(dev, "Unexpected preamble received\n");
isr_clr |= FSL_XCVR_IRQ_UNEXP_PRE_REC;
}
if (isr & FSL_XCVR_IRQ_M_W_PRE_MISMATCH) {
dev_dbg(dev, "M/W preamble mismatch\n");
isr_clr |= FSL_XCVR_IRQ_M_W_PRE_MISMATCH;
}
if (isr & FSL_XCVR_IRQ_B_PRE_MISMATCH) {
dev_dbg(dev, "B preamble mismatch\n");
isr_clr |= FSL_XCVR_IRQ_B_PRE_MISMATCH;
}
if (isr & (FSL_XCVR_IRQ_PREAMBLE_MISMATCH |
FSL_XCVR_IRQ_UNEXP_PRE_REC |
FSL_XCVR_IRQ_M_W_PRE_MISMATCH |
FSL_XCVR_IRQ_B_PRE_MISMATCH)) {
schedule_work(&xcvr->work_rst);
}
if (isr_clr) {
regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
.fw_name = "imx/xcvr/xcvr-imx8mp.bin",
.use_phy = true,
.pll_ver = PLL_MX8MP,
};
static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
.spdif_only = true,
.use_edma = true,
};
static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
.fw_name = "imx/xcvr/xcvr-imx95.bin",
.spdif_only = true,
.use_phy = true,
.use_edma = true,
.pll_ver = PLL_MX95,
};
static const struct of_device_id fsl_xcvr_dt_ids[] = {
{ .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
{ .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data},
{ .compatible = "fsl,imx95-xcvr", .data = &fsl_xcvr_imx95_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);