mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-29 10:34:22 -04:00
media: rcar-csi2: Add r8a779a0 support
Add support for the R-Car V3U (r8a779a0) to the driver. The V3U have the CSI-2 modules connected to ISPs instead of directly to the R-Car VIN DMA engines. The ISP performs channel selection based on CSI-2 VC/DT pairs and routes the video data. This requires the R-Car CSI-2 media entity to modeled differently then on other SoCs as it on the V3U only have a single source pad connected to the ISP. Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
c624fe63c0
commit
b4173cd998
@@ -126,6 +126,12 @@ struct rcar_csi2;
|
||||
#define PHTW_CWEN BIT(8)
|
||||
#define PHTW_TESTDIN_CODE(n) ((n & 0xff))
|
||||
|
||||
#define PHYFRX_REG 0x64
|
||||
#define PHYFRX_FORCERX_MODE_3 BIT(3)
|
||||
#define PHYFRX_FORCERX_MODE_2 BIT(2)
|
||||
#define PHYFRX_FORCERX_MODE_1 BIT(1)
|
||||
#define PHYFRX_FORCERX_MODE_0 BIT(0)
|
||||
|
||||
struct phtw_value {
|
||||
u16 data;
|
||||
u16 code;
|
||||
@@ -136,6 +142,31 @@ struct rcsi2_mbps_reg {
|
||||
u16 reg;
|
||||
};
|
||||
|
||||
static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
|
||||
{ .mbps = 1500, .reg = 0xcc },
|
||||
{ .mbps = 1550, .reg = 0x1d },
|
||||
{ .mbps = 1600, .reg = 0x27 },
|
||||
{ .mbps = 1650, .reg = 0x30 },
|
||||
{ .mbps = 1700, .reg = 0x39 },
|
||||
{ .mbps = 1750, .reg = 0x42 },
|
||||
{ .mbps = 1800, .reg = 0x4b },
|
||||
{ .mbps = 1850, .reg = 0x55 },
|
||||
{ .mbps = 1900, .reg = 0x5e },
|
||||
{ .mbps = 1950, .reg = 0x67 },
|
||||
{ .mbps = 2000, .reg = 0x71 },
|
||||
{ .mbps = 2050, .reg = 0x79 },
|
||||
{ .mbps = 2100, .reg = 0x83 },
|
||||
{ .mbps = 2150, .reg = 0x8c },
|
||||
{ .mbps = 2200, .reg = 0x95 },
|
||||
{ .mbps = 2250, .reg = 0x9e },
|
||||
{ .mbps = 2300, .reg = 0xa7 },
|
||||
{ .mbps = 2350, .reg = 0xb0 },
|
||||
{ .mbps = 2400, .reg = 0xba },
|
||||
{ .mbps = 2450, .reg = 0xc3 },
|
||||
{ .mbps = 2500, .reg = 0xcc },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
|
||||
{ .mbps = 80, .reg = 0x86 },
|
||||
{ .mbps = 90, .reg = 0x86 },
|
||||
@@ -200,6 +231,72 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
|
||||
#define PHYPLL_REG 0x68
|
||||
#define PHYPLL_HSFREQRANGE(n) ((n) << 16)
|
||||
|
||||
static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
|
||||
{ .mbps = 80, .reg = 0x00 },
|
||||
{ .mbps = 90, .reg = 0x10 },
|
||||
{ .mbps = 100, .reg = 0x20 },
|
||||
{ .mbps = 110, .reg = 0x30 },
|
||||
{ .mbps = 120, .reg = 0x01 },
|
||||
{ .mbps = 130, .reg = 0x11 },
|
||||
{ .mbps = 140, .reg = 0x21 },
|
||||
{ .mbps = 150, .reg = 0x31 },
|
||||
{ .mbps = 160, .reg = 0x02 },
|
||||
{ .mbps = 170, .reg = 0x12 },
|
||||
{ .mbps = 180, .reg = 0x22 },
|
||||
{ .mbps = 190, .reg = 0x32 },
|
||||
{ .mbps = 205, .reg = 0x03 },
|
||||
{ .mbps = 220, .reg = 0x13 },
|
||||
{ .mbps = 235, .reg = 0x23 },
|
||||
{ .mbps = 250, .reg = 0x33 },
|
||||
{ .mbps = 275, .reg = 0x04 },
|
||||
{ .mbps = 300, .reg = 0x14 },
|
||||
{ .mbps = 325, .reg = 0x25 },
|
||||
{ .mbps = 350, .reg = 0x35 },
|
||||
{ .mbps = 400, .reg = 0x05 },
|
||||
{ .mbps = 450, .reg = 0x16 },
|
||||
{ .mbps = 500, .reg = 0x26 },
|
||||
{ .mbps = 550, .reg = 0x37 },
|
||||
{ .mbps = 600, .reg = 0x07 },
|
||||
{ .mbps = 650, .reg = 0x18 },
|
||||
{ .mbps = 700, .reg = 0x28 },
|
||||
{ .mbps = 750, .reg = 0x39 },
|
||||
{ .mbps = 800, .reg = 0x09 },
|
||||
{ .mbps = 850, .reg = 0x19 },
|
||||
{ .mbps = 900, .reg = 0x29 },
|
||||
{ .mbps = 950, .reg = 0x3a },
|
||||
{ .mbps = 1000, .reg = 0x0a },
|
||||
{ .mbps = 1050, .reg = 0x1a },
|
||||
{ .mbps = 1100, .reg = 0x2a },
|
||||
{ .mbps = 1150, .reg = 0x3b },
|
||||
{ .mbps = 1200, .reg = 0x0b },
|
||||
{ .mbps = 1250, .reg = 0x1b },
|
||||
{ .mbps = 1300, .reg = 0x2b },
|
||||
{ .mbps = 1350, .reg = 0x3c },
|
||||
{ .mbps = 1400, .reg = 0x0c },
|
||||
{ .mbps = 1450, .reg = 0x1c },
|
||||
{ .mbps = 1500, .reg = 0x2c },
|
||||
{ .mbps = 1550, .reg = 0x3d },
|
||||
{ .mbps = 1600, .reg = 0x0d },
|
||||
{ .mbps = 1650, .reg = 0x1d },
|
||||
{ .mbps = 1700, .reg = 0x2e },
|
||||
{ .mbps = 1750, .reg = 0x3e },
|
||||
{ .mbps = 1800, .reg = 0x0e },
|
||||
{ .mbps = 1850, .reg = 0x1e },
|
||||
{ .mbps = 1900, .reg = 0x2f },
|
||||
{ .mbps = 1950, .reg = 0x3f },
|
||||
{ .mbps = 2000, .reg = 0x0f },
|
||||
{ .mbps = 2050, .reg = 0x40 },
|
||||
{ .mbps = 2100, .reg = 0x41 },
|
||||
{ .mbps = 2150, .reg = 0x42 },
|
||||
{ .mbps = 2200, .reg = 0x43 },
|
||||
{ .mbps = 2300, .reg = 0x45 },
|
||||
{ .mbps = 2350, .reg = 0x46 },
|
||||
{ .mbps = 2400, .reg = 0x47 },
|
||||
{ .mbps = 2450, .reg = 0x48 },
|
||||
{ .mbps = 2500, .reg = 0x49 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
|
||||
{ .mbps = 80, .reg = 0x00 },
|
||||
{ .mbps = 90, .reg = 0x10 },
|
||||
@@ -355,6 +452,7 @@ struct rcar_csi2_info {
|
||||
unsigned int csi0clkfreqrange;
|
||||
unsigned int num_channels;
|
||||
bool clear_ulps;
|
||||
bool use_isp;
|
||||
};
|
||||
|
||||
struct rcar_csi2 {
|
||||
@@ -609,9 +707,12 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
|
||||
rcsi2_write(priv, PHTC_REG, 0);
|
||||
|
||||
/* Configure */
|
||||
rcsi2_write(priv, VCDT_REG, vcdt);
|
||||
if (vcdt2)
|
||||
rcsi2_write(priv, VCDT2_REG, vcdt2);
|
||||
if (!priv->info->use_isp) {
|
||||
rcsi2_write(priv, VCDT_REG, vcdt);
|
||||
if (vcdt2)
|
||||
rcsi2_write(priv, VCDT2_REG, vcdt2);
|
||||
}
|
||||
|
||||
/* Lanes are zero indexed. */
|
||||
rcsi2_write(priv, LSWAP_REG,
|
||||
LSWAP_L0SEL(priv->lane_swap[0] - 1) |
|
||||
@@ -636,6 +737,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
|
||||
rcsi2_write(priv, CSI0CLKFCPR_REG,
|
||||
CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
|
||||
|
||||
if (priv->info->use_isp)
|
||||
rcsi2_write(priv, PHYFRX_REG,
|
||||
PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 |
|
||||
PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0);
|
||||
|
||||
rcsi2_write(priv, PHYCNT_REG, phycnt);
|
||||
rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
|
||||
LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
|
||||
@@ -647,6 +753,9 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->info->use_isp)
|
||||
rcsi2_write(priv, PHYFRX_REG, 0);
|
||||
|
||||
/* Run post PHY start initialization, if needed. */
|
||||
if (priv->info->phy_post_init) {
|
||||
ret = priv->info->phy_post_init(priv);
|
||||
@@ -1063,6 +1172,62 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv)
|
||||
return rcsi2_phtw_write_array(priv, step1);
|
||||
}
|
||||
|
||||
static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
|
||||
unsigned int mbps)
|
||||
{
|
||||
/* In case of 1500Mbps or less */
|
||||
static const struct phtw_value step1[] = {
|
||||
{ .data = 0xcc, .code = 0xe2 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct phtw_value step2[] = {
|
||||
{ .data = 0x01, .code = 0xe3 },
|
||||
{ .data = 0x11, .code = 0xe4 },
|
||||
{ .data = 0x01, .code = 0xe5 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
/* In case of 1500Mbps or less */
|
||||
static const struct phtw_value step3[] = {
|
||||
{ .data = 0x38, .code = 0x08 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct phtw_value step4[] = {
|
||||
{ .data = 0x01, .code = 0x00 },
|
||||
{ .data = 0x4b, .code = 0xac },
|
||||
{ .data = 0x03, .code = 0x00 },
|
||||
{ .data = 0x80, .code = 0x07 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
int ret;
|
||||
|
||||
if (mbps != 0 && mbps <= 1500)
|
||||
ret = rcsi2_phtw_write_array(priv, step1);
|
||||
else
|
||||
ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rcsi2_phtw_write_array(priv, step2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mbps != 0 && mbps <= 1500) {
|
||||
ret = rcsi2_phtw_write_array(priv, step3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rcsi2_phtw_write_array(priv, step4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Platform Device Driver.
|
||||
*/
|
||||
@@ -1155,6 +1320,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
|
||||
.num_channels = 2,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
|
||||
.init_phtw = rcsi2_init_phtw_v3u,
|
||||
.hsfreqrange = hsfreqrange_v3u,
|
||||
.csi0clkfreqrange = 0x20,
|
||||
.clear_ulps = true,
|
||||
.use_isp = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_csi2_of_table[] = {
|
||||
{
|
||||
.compatible = "renesas,r8a774a1-csi2",
|
||||
@@ -1200,6 +1373,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
|
||||
.compatible = "renesas,r8a77990-csi2",
|
||||
.data = &rcar_csi2_info_r8a77990,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r8a779a0-csi2",
|
||||
.data = &rcar_csi2_info_r8a779a0,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
|
||||
@@ -1220,7 +1397,7 @@ static int rcsi2_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct soc_device_attribute *attr;
|
||||
struct rcar_csi2 *priv;
|
||||
unsigned int i;
|
||||
unsigned int i, num_pads;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -1265,11 +1442,13 @@ static int rcsi2_probe(struct platform_device *pdev)
|
||||
priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
|
||||
priv->subdev.entity.ops = &rcar_csi2_entity_ops;
|
||||
|
||||
num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD;
|
||||
|
||||
priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
for (i = RCAR_CSI2_SOURCE_VC0; i < NR_OF_RCAR_CSI2_PAD; i++)
|
||||
for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
|
||||
priv->pads[i].flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
ret = media_entity_pads_init(&priv->subdev.entity, NR_OF_RCAR_CSI2_PAD,
|
||||
ret = media_entity_pads_init(&priv->subdev.entity, num_pads,
|
||||
priv->pads);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
Reference in New Issue
Block a user