Загрузка данных


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);