Commit 050ff2ad authored by Jan Kotas's avatar Jan Kotas Committed by Mauro Carvalho Chehab
Browse files

media: Add support for Cadence CSI2TX 2.1



This patch adds support for CSI2TX v2.1 version of the controller.

Signed-off-by: default avatarJan Kotas <jank@cadence.com>
Acked-by: default avatarMaxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 6ded416d
Loading
Loading
Loading
Loading
+111 −29
Original line number Diff line number Diff line
@@ -52,6 +52,17 @@
#define CSI2TX_STREAM_IF_CFG_REG(n)	(0x100 + (n) * 4)
#define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n)	((n) & 0x1f)

/* CSI2TX V2 Registers */
#define CSI2TX_V2_DPHY_CFG_REG			0x28
#define CSI2TX_V2_DPHY_CFG_RESET		BIT(16)
#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE		BIT(10)
#define CSI2TX_V2_DPHY_CFG_MODE_MASK		GENMASK(9, 8)
#define CSI2TX_V2_DPHY_CFG_MODE_LPDT		(2 << 8)
#define CSI2TX_V2_DPHY_CFG_MODE_HS		(1 << 8)
#define CSI2TX_V2_DPHY_CFG_MODE_ULPS		(0 << 8)
#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE		BIT(4)
#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n)	BIT(n)

#define CSI2TX_LANES_MAX	4
#define CSI2TX_STREAMS_MAX	4

@@ -70,6 +81,13 @@ struct csi2tx_fmt {
	u32	bpp;
};

struct csi2tx_priv;

/* CSI2TX Variant Operations */
struct csi2tx_vops {
	void (*dphy_setup)(struct csi2tx_priv *csi2tx);
};

struct csi2tx_priv {
	struct device			*dev;
	unsigned int			count;
@@ -82,6 +100,8 @@ struct csi2tx_priv {

	void __iomem			*base;

	struct csi2tx_vops		*vops;

	struct clk			*esc_clk;
	struct clk			*p_clk;
	struct clk			*pixel_clk[CSI2TX_STREAMS_MAX];
@@ -209,29 +229,44 @@ static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = {
	.set_fmt	= csi2tx_set_pad_format,
};

static void csi2tx_reset(struct csi2tx_priv *csi2tx)
/* Set Wake Up value in the D-PHY */
static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx)
{
	writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);

	udelay(10);
	writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
	       csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
}

static int csi2tx_start(struct csi2tx_priv *csi2tx)
/*
 * Finishes the D-PHY initialization
 * reg dphy cfg value to be used
 */
static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg)
{
	struct media_entity *entity = &csi2tx->subdev.entity;
	struct media_link *link;
	unsigned int i;
	u32 reg;

	csi2tx_reset(csi2tx);
	udelay(10);

	writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
	/* Enable our (clock and data) lanes */
	reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
	for (i = 0; i < csi2tx->num_lanes; i++)
		reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1);
	writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);

	udelay(10);

	/* Configure our PPI interface with the D-PHY */
	writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
	       csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
	/* Switch to HS mode */
	reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
	writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
	       csi2tx->base + CSI2TX_DPHY_CFG_REG);
}

/* Configures D-PHY in CSIv1.3 */
static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx)
{
	u32 reg;
	unsigned int i;

	csi2tx_dphy_set_wakeup(csi2tx);

	/* Put our lanes (clock and data) out of reset */
	reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT;
@@ -239,23 +274,47 @@ static int csi2tx_start(struct csi2tx_priv *csi2tx)
		reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1);
	writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);

	udelay(10);
	csi2tx_dphy_init_finish(csi2tx, reg);
}

	/* Enable our (clock and data) lanes */
	reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
	for (i = 0; i < csi2tx->num_lanes; i++)
		reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1);
	writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
/* Configures D-PHY in CSIv2 */
static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx)
{
	u32 reg;

	csi2tx_dphy_set_wakeup(csi2tx);

	/* Put our lanes (clock and data) out of reset */
	reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT;
	writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG);

	csi2tx_dphy_init_finish(csi2tx, reg);
}

static void csi2tx_reset(struct csi2tx_priv *csi2tx)
{
	writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);

	udelay(10);
}

	/* Switch to HS mode */
	reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
	writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
	       csi2tx->base + CSI2TX_DPHY_CFG_REG);
static int csi2tx_start(struct csi2tx_priv *csi2tx)
{
	struct media_entity *entity = &csi2tx->subdev.entity;
	struct media_link *link;
	unsigned int i;

	csi2tx_reset(csi2tx);

	writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG);

	udelay(10);

	if (csi2tx->vops && csi2tx->vops->dphy_setup) {
		csi2tx->vops->dphy_setup(csi2tx);
		udelay(10);
	}

	/*
	 * Create a static mapping between the CSI virtual channels
	 * and the input streams.
@@ -478,9 +537,35 @@ out:
	return ret;
}

static const struct csi2tx_vops csi2tx_vops = {
	.dphy_setup = csi2tx_dphy_setup,
};

static const struct csi2tx_vops csi2tx_v2_vops = {
	.dphy_setup = csi2tx_v2_dphy_setup,
};

static const struct of_device_id csi2tx_of_table[] = {
	{
		.compatible = "cdns,csi2tx",
		.data = &csi2tx_vops
	},
	{
		.compatible = "cdns,csi2tx-1.3",
		.data = &csi2tx_vops
	},
	{
		.compatible = "cdns,csi2tx-2.1",
		.data = &csi2tx_v2_vops
	},
	{ }
};
MODULE_DEVICE_TABLE(of, csi2tx_of_table);

static int csi2tx_probe(struct platform_device *pdev)
{
	struct csi2tx_priv *csi2tx;
	const struct of_device_id *of_id;
	unsigned int i;
	int ret;

@@ -495,6 +580,9 @@ static int csi2tx_probe(struct platform_device *pdev)
	if (ret)
		goto err_free_priv;

	of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node);
	csi2tx->vops = (struct csi2tx_vops *)of_id->data;

	v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops);
	csi2tx->subdev.owner = THIS_MODULE;
	csi2tx->subdev.dev = &pdev->dev;
@@ -552,12 +640,6 @@ static int csi2tx_remove(struct platform_device *pdev)
	return 0;
}

static const struct of_device_id csi2tx_of_table[] = {
	{ .compatible = "cdns,csi2tx" },
	{ },
};
MODULE_DEVICE_TABLE(of, csi2tx_of_table);

static struct platform_driver csi2tx_driver = {
	.probe	= csi2tx_probe,
	.remove	= csi2tx_remove,