Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/media/platform/qcom/camss/camss-csid-gen2.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ static void __csid_configure_rx(struct csid_device *csid,
val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
val |= phy->csiphy_id << CSI2_RX_CFG0_PHY_NUM_SEL;
val |= csid->phy.phy_sel << CSI2_RX_CFG0_PHY_TYPE_SEL;
writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0);

val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/platform/qcom/camss/camss-csid-gen3.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#define CSI2_RX_CFG0_VC_MODE 3
#define CSI2_RX_CFG0_DL0_INPUT_SEL 4
#define CSI2_RX_CFG0_PHY_NUM_SEL 20
#define CSI2_RX_CFG0_PHY_TYPE_SEL 24
#define CSI2_RX_CFG0_TPG_MUX_EN BIT(27)
#define CSI2_RX_CFG0_TPG_MUX_SEL GENMASK(29, 28)

Expand Down Expand Up @@ -115,6 +116,7 @@ static void __csid_configure_rx(struct csid_device *csid,

camss = csid->camss;
val = (phy->lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
val |= phy->phy_sel << CSI2_RX_CFG0_PHY_TYPE_SEL;
val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;

if (camss->tpg && csid->tpg_linked &&
Expand Down
11 changes: 9 additions & 2 deletions drivers/media/platform/qcom/camss/camss-csid.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,14 +540,16 @@ static int csid_set_clock_rates(struct csid_device *csid)
{
struct device *dev = csid->camss->dev;
const struct csid_format_info *fmt;
const bool cphy = (csid->phy.phy_sel == CSID_PHY_SEL_CPHY);

s64 link_freq;
int i, j;
int ret;

fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats,
csid->fmt[MSM_CSIPHY_PAD_SINK].code);
link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp,
csid->phy.lane_cnt);

link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, csid->phy.lane_cnt, cphy);
if (link_freq < 0)
link_freq = 0;

Expand Down Expand Up @@ -1291,6 +1293,11 @@ static int csid_link_setup(struct media_entity *entity,

lane_cfg = &csiphy->cfg.csi2->lane_cfg;
csid->phy.lane_cnt = lane_cfg->num_data;
if (lane_cfg->phy_cfg == V4L2_MBUS_CSI2_CPHY)
csid->phy.phy_sel = CSID_PHY_SEL_CPHY;
else
csid->phy.phy_sel = CSID_PHY_SEL_DPHY;

csid->phy.lane_assign = csid_get_lane_assign(lane_cfg, lane_cfg->num_data);
csid->tpg_linked = false;
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/media/platform/qcom/camss/camss-csid.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ enum csid_testgen_mode {
CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */
};

enum csid_phy_sel {
CSID_PHY_SEL_DPHY = 0,
CSID_PHY_SEL_CPHY = 1
};

struct csid_format_info {
u32 code;
u8 data_type;
Expand All @@ -70,6 +75,7 @@ struct csid_phy_config {
u32 lane_assign;
u32 en_vc;
u8 need_vc_update;
enum csid_phy_sel phy_sel;
};

struct csid_device;
Expand Down
606 changes: 557 additions & 49 deletions drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions drivers/media/platform/qcom/camss/camss-csiphy.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ static int csiphy_set_clock_rates_legacy(struct csiphy_device *csiphy)
u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
const bool cphy = (csiphy->cfg.csi2->lane_cfg.phy_cfg == V4L2_MBUS_CSI2_CPHY);

link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes, cphy);
if (link_freq < 0)
link_freq = 0;

Expand Down Expand Up @@ -272,9 +273,10 @@ static int csiphy_stream_on_legacy(struct csiphy_device *csiphy)
u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
const bool cphy = (csiphy->cfg.csi2->lane_cfg.phy_cfg == V4L2_MBUS_CSI2_CPHY);
u8 val;

link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes, cphy);

if (link_freq < 0) {
dev_err(csiphy->camss->dev,
Expand Down Expand Up @@ -331,13 +333,14 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
union phy_configure_opts dphy_opts = { 0 };
struct device *dev = csiphy->camss->dev;
u8 num_lanes = lncfg->num_data;
const bool cphy = (lncfg->phy_cfg == V4L2_MBUS_CSI2_CPHY);
s64 link_freq;
int i;
int ret;

dphy_cfg = &dphy_opts.mipi_dphy;

link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes, cphy);

if (link_freq < 0) {
dev_err(dev,
Expand Down
8 changes: 8 additions & 0 deletions drivers/media/platform/qcom/camss/camss-csiphy.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ struct csiphy_lane {

/**
* struct csiphy_lanes_cfg - CSIPHY lanes configuration
* @phy_cfg: interface selection (C-PHY or D-PHY)
* @num_data: number of data lanes
* @data: data lanes configuration
* @clk: clock lane configuration (only for D-PHY)
*/
struct csiphy_lanes_cfg {
enum v4l2_mbus_type phy_cfg;
int num_data;
struct csiphy_lane *data;
struct csiphy_lane clk;
Expand All @@ -61,6 +63,12 @@ struct csiphy_formats {
const struct csiphy_format_info *formats;
};

struct data_rate_reg_info {
u64 bandwidth;
ssize_t data_rate_reg_array_size;
struct csiphy_lane_regs *data_rate_reg_array;
};

struct csiphy_device;

struct csiphy_hw_ops {
Expand Down
61 changes: 51 additions & 10 deletions drivers/media/platform/qcom/camss/camss.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
#define CAMSS_CLOCK_MARGIN_NUMERATOR 105
#define CAMSS_CLOCK_MARGIN_DENOMINATOR 100

/*
* C-PHY encodes data by 16/7 ~ 2.28 bits/symbol
* D-PHY doesn't encode data, thus 16/16 = 1 b/s
*/
#define CAMSS_COMMON_PHY_DIVIDENT 16
#define CAMSS_CPHY_DIVISOR 7
#define CAMSS_DPHY_DIVISOR 16

static const struct parent_dev_ops vfe_parent_dev_ops;

static const struct camss_subdev_resources csiphy_res_8x16[] = {
Expand Down Expand Up @@ -4434,19 +4442,22 @@ struct media_pad *camss_find_sensor_pad(struct media_entity *entity)
* @entity: Media entity in the current pipeline
* @bpp: Number of bits per pixel for the current format
* @lanes: Number of lanes in the link to the sensor
* @cphy: If C-PHY encoding is used.
*
* Return link frequency on success or a negative error code otherwise
*/
s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp,
unsigned int lanes)
unsigned int lanes, const bool cphy)
{
struct media_pad *sensor_pad;
unsigned int div = lanes * 2 * (cphy ? CAMSS_CPHY_DIVISOR :
CAMSS_DPHY_DIVISOR);

sensor_pad = camss_find_sensor_pad(entity);
if (!sensor_pad)
return -ENODEV;

return v4l2_get_link_freq(sensor_pad, bpp, 2 * lanes);
return v4l2_get_link_freq(sensor_pad, CAMSS_COMMON_PHY_DIVIDENT * bpp, div);
}

/*
Expand Down Expand Up @@ -4556,29 +4567,59 @@ static int camss_parse_endpoint_node(struct device *dev,
{
struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg;
struct v4l2_mbus_config_mipi_csi2 *mipi_csi2;
struct v4l2_fwnode_endpoint vep = { { 0 } };
struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_UNKNOWN };
struct v4l2_fwnode_endpoint remote_vep = { .bus_type = V4L2_MBUS_UNKNOWN };
struct fwnode_handle *remote_ep;
unsigned int i;
int ret;

ret = v4l2_fwnode_endpoint_parse(ep, &vep);
if (ret)
return ret;

/*
* Most SoCs support both D-PHY and C-PHY standards, but currently only
* D-PHY is supported in the driver.
*/
if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) {
switch (vep.bus_type) {
case V4L2_MBUS_CSI2_CPHY:
case V4L2_MBUS_CSI2_DPHY:
break;
default:
dev_err(dev, "Unsupported bus type %d\n", vep.bus_type);
return -EINVAL;
}

/* Get the remote (sensor) endpoint handle, e.g. imx686_ep1 */
remote_ep = fwnode_graph_get_remote_endpoint(ep);
if (!remote_ep) {
dev_dbg(dev, "No remote endpoint found for %pfw\n", ep);
return -ENODEV;
}

/* Parse the remote bus type and release the handle */
ret = v4l2_fwnode_endpoint_parse(remote_ep, &remote_vep);
fwnode_handle_put(remote_ep);
if (ret) {
dev_dbg(dev, "Failed to parse remote endpoint\n");
return ret;
}

/* The local (CSIPHY) and remote (sensor) ends must agree */
if (vep.bus_type != remote_vep.bus_type) {
dev_dbg(dev, "Bus type mismatch! Local (CSI-PHY): %u, Remote (Sensor): %u\n",
vep.bus_type, remote_vep.bus_type);
return -EINVAL;
}

dev_dbg(dev, "Verified link: both ends use bus-type %u\n", vep.bus_type);

csd->interface.csiphy_id = vep.base.port;

mipi_csi2 = &vep.bus.mipi_csi2;
lncfg->clk.pos = mipi_csi2->clock_lane;
lncfg->clk.pol = mipi_csi2->lane_polarities[0];
lncfg->num_data = mipi_csi2->num_data_lanes;
lncfg->phy_cfg = vep.bus_type;

if (lncfg->phy_cfg != V4L2_MBUS_CSI2_CPHY) {
lncfg->clk.pos = mipi_csi2->clock_lane;
lncfg->clk.pol = mipi_csi2->lane_polarities[0];
}

lncfg->data = devm_kcalloc(dev,
lncfg->num_data, sizeof(*lncfg->data),
Expand Down
2 changes: 1 addition & 1 deletion drivers/media/platform/qcom/camss/camss.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock,
void camss_disable_clocks(int nclocks, struct camss_clock *clock);
struct media_pad *camss_find_sensor_pad(struct media_entity *entity);
s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp,
unsigned int lanes);
unsigned int lanes, const bool cphy);
int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock);
int camss_pm_domain_on(struct camss *camss, int id);
void camss_pm_domain_off(struct camss *camss, int id);
Expand Down
Loading