|
@@ -23,18 +23,6 @@
|
|
|
|
|
|
#define MSM_CSIPHY_NAME "msm_csiphy"
|
|
|
|
|
|
-#define CAMSS_CSI_PHY_LNn_CFG2(n) (0x004 + 0x40 * (n))
|
|
|
-#define CAMSS_CSI_PHY_LNn_CFG3(n) (0x008 + 0x40 * (n))
|
|
|
-#define CAMSS_CSI_PHY_GLBL_RESET 0x140
|
|
|
-#define CAMSS_CSI_PHY_GLBL_PWR_CFG 0x144
|
|
|
-#define CAMSS_CSI_PHY_GLBL_IRQ_CMD 0x164
|
|
|
-#define CAMSS_CSI_PHY_HW_VERSION 0x188
|
|
|
-#define CAMSS_CSI_PHY_INTERRUPT_STATUSn(n) (0x18c + 0x4 * (n))
|
|
|
-#define CAMSS_CSI_PHY_INTERRUPT_MASKn(n) (0x1ac + 0x4 * (n))
|
|
|
-#define CAMSS_CSI_PHY_INTERRUPT_CLEARn(n) (0x1cc + 0x4 * (n))
|
|
|
-#define CAMSS_CSI_PHY_GLBL_T_INIT_CFG0 0x1ec
|
|
|
-#define CAMSS_CSI_PHY_T_WAKEUP_CFG0 0x1f4
|
|
|
-
|
|
|
static const struct {
|
|
|
u32 code;
|
|
|
u8 bpp;
|
|
@@ -124,32 +112,6 @@ static u8 csiphy_get_bpp(u32 code)
|
|
|
return csiphy_formats[0].bpp;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * csiphy_isr - CSIPHY module interrupt handler
|
|
|
- * @irq: Interrupt line
|
|
|
- * @dev: CSIPHY device
|
|
|
- *
|
|
|
- * Return IRQ_HANDLED on success
|
|
|
- */
|
|
|
-static irqreturn_t csiphy_isr(int irq, void *dev)
|
|
|
-{
|
|
|
- struct csiphy_device *csiphy = dev;
|
|
|
- u8 i;
|
|
|
-
|
|
|
- for (i = 0; i < 8; i++) {
|
|
|
- u8 val = readl_relaxed(csiphy->base +
|
|
|
- CAMSS_CSI_PHY_INTERRUPT_STATUSn(i));
|
|
|
- writel_relaxed(val, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_INTERRUPT_CLEARn(i));
|
|
|
- writel_relaxed(0x1, csiphy->base + CAMSS_CSI_PHY_GLBL_IRQ_CMD);
|
|
|
- writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_IRQ_CMD);
|
|
|
- writel_relaxed(0x0, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_INTERRUPT_CLEARn(i));
|
|
|
- }
|
|
|
-
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* csiphy_set_clock_rates - Calculate and set clock rates on CSIPHY module
|
|
|
* @csiphy: CSIPHY device
|
|
@@ -214,17 +176,6 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * csiphy_reset - Perform software reset on CSIPHY module
|
|
|
- * @csiphy: CSIPHY device
|
|
|
- */
|
|
|
-static void csiphy_reset(struct csiphy_device *csiphy)
|
|
|
-{
|
|
|
- writel_relaxed(0x1, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET);
|
|
|
- usleep_range(5000, 8000);
|
|
|
- writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* csiphy_set_power - Power on/off CSIPHY module
|
|
|
* @sd: CSIPHY V4L2 subdevice
|
|
@@ -238,7 +189,6 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
|
|
|
struct device *dev = csiphy->camss->dev;
|
|
|
|
|
|
if (on) {
|
|
|
- u8 hw_version;
|
|
|
int ret;
|
|
|
|
|
|
ret = pm_runtime_get_sync(dev);
|
|
@@ -259,11 +209,9 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
|
|
|
|
|
|
enable_irq(csiphy->irq);
|
|
|
|
|
|
- csiphy_reset(csiphy);
|
|
|
+ csiphy->ops->reset(csiphy);
|
|
|
|
|
|
- hw_version = readl_relaxed(csiphy->base +
|
|
|
- CAMSS_CSI_PHY_HW_VERSION);
|
|
|
- dev_dbg(dev, "CSIPHY HW Version = 0x%02x\n", hw_version);
|
|
|
+ csiphy->ops->hw_version_read(csiphy, dev);
|
|
|
} else {
|
|
|
disable_irq(csiphy->irq);
|
|
|
|
|
@@ -295,77 +243,34 @@ static u8 csiphy_get_lane_mask(struct csiphy_lanes_cfg *lane_cfg)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * csiphy_settle_cnt_calc - Calculate settle count value
|
|
|
+ * csiphy_stream_on - Enable streaming on CSIPHY module
|
|
|
* @csiphy: CSIPHY device
|
|
|
*
|
|
|
- * Helper function to calculate settle count value. This is
|
|
|
- * based on the CSI2 T_hs_settle parameter which in turn
|
|
|
- * is calculated based on the CSI2 transmitter pixel clock
|
|
|
- * frequency.
|
|
|
+ * Helper function to enable streaming on CSIPHY module.
|
|
|
+ * Main configuration of CSIPHY module is also done here.
|
|
|
*
|
|
|
- * Return settle count value or 0 if the CSI2 pixel clock
|
|
|
- * frequency is not available
|
|
|
+ * Return 0 on success or a negative error code otherwise
|
|
|
*/
|
|
|
-static u8 csiphy_settle_cnt_calc(struct csiphy_device *csiphy)
|
|
|
+static int csiphy_stream_on(struct csiphy_device *csiphy)
|
|
|
{
|
|
|
- u8 bpp = csiphy_get_bpp(
|
|
|
- csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
|
|
|
- u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
|
|
|
- u32 pixel_clock; /* Hz */
|
|
|
- u32 mipi_clock; /* Hz */
|
|
|
- u32 ui; /* ps */
|
|
|
- u32 timer_period; /* ps */
|
|
|
- u32 t_hs_prepare_max; /* ps */
|
|
|
- u32 t_hs_prepare_zero_min; /* ps */
|
|
|
- u32 t_hs_settle; /* ps */
|
|
|
- u8 settle_cnt;
|
|
|
+ struct csiphy_config *cfg = &csiphy->cfg;
|
|
|
+ u32 pixel_clock;
|
|
|
+ u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg);
|
|
|
+ u8 bpp = csiphy_get_bpp(csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
|
|
|
+ u8 val;
|
|
|
int ret;
|
|
|
|
|
|
ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock);
|
|
|
if (ret) {
|
|
|
dev_err(csiphy->camss->dev,
|
|
|
"Cannot get CSI2 transmitter's pixel clock\n");
|
|
|
- return 0;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
if (!pixel_clock) {
|
|
|
dev_err(csiphy->camss->dev,
|
|
|
"Got pixel clock == 0, cannot continue\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- mipi_clock = pixel_clock * bpp / (2 * num_lanes);
|
|
|
- ui = div_u64(1000000000000LL, mipi_clock);
|
|
|
- ui /= 2;
|
|
|
- t_hs_prepare_max = 85000 + 6 * ui;
|
|
|
- t_hs_prepare_zero_min = 145000 + 10 * ui;
|
|
|
- t_hs_settle = (t_hs_prepare_max + t_hs_prepare_zero_min) / 2;
|
|
|
-
|
|
|
- timer_period = div_u64(1000000000000LL, csiphy->timer_clk_rate);
|
|
|
- settle_cnt = t_hs_settle / timer_period - 1;
|
|
|
-
|
|
|
- return settle_cnt;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * csiphy_stream_on - Enable streaming on CSIPHY module
|
|
|
- * @csiphy: CSIPHY device
|
|
|
- *
|
|
|
- * Helper function to enable streaming on CSIPHY module.
|
|
|
- * Main configuration of CSIPHY module is also done here.
|
|
|
- *
|
|
|
- * Return 0 on success or a negative error code otherwise
|
|
|
- */
|
|
|
-static int csiphy_stream_on(struct csiphy_device *csiphy)
|
|
|
-{
|
|
|
- struct csiphy_config *cfg = &csiphy->cfg;
|
|
|
- u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg);
|
|
|
- u8 settle_cnt;
|
|
|
- u8 val;
|
|
|
- int i = 0;
|
|
|
-
|
|
|
- settle_cnt = csiphy_settle_cnt_calc(csiphy);
|
|
|
- if (!settle_cnt)
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
val = readl_relaxed(csiphy->base_clk_mux);
|
|
|
if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
|
|
@@ -378,33 +283,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
|
|
|
writel_relaxed(val, csiphy->base_clk_mux);
|
|
|
wmb();
|
|
|
|
|
|
- writel_relaxed(0x1, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_GLBL_T_INIT_CFG0);
|
|
|
- writel_relaxed(0x1, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_T_WAKEUP_CFG0);
|
|
|
-
|
|
|
- val = 0x1;
|
|
|
- val |= lane_mask << 1;
|
|
|
- writel_relaxed(val, csiphy->base + CAMSS_CSI_PHY_GLBL_PWR_CFG);
|
|
|
-
|
|
|
- val = cfg->combo_mode << 4;
|
|
|
- writel_relaxed(val, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET);
|
|
|
-
|
|
|
- while (lane_mask) {
|
|
|
- if (lane_mask & 0x1) {
|
|
|
- writel_relaxed(0x10, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_LNn_CFG2(i));
|
|
|
- writel_relaxed(settle_cnt, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_LNn_CFG3(i));
|
|
|
- writel_relaxed(0x3f, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_INTERRUPT_MASKn(i));
|
|
|
- writel_relaxed(0x3f, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_INTERRUPT_CLEARn(i));
|
|
|
- }
|
|
|
-
|
|
|
- lane_mask >>= 1;
|
|
|
- i++;
|
|
|
- }
|
|
|
+ csiphy->ops->lanes_enable(csiphy, cfg, pixel_clock, bpp, lane_mask);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -418,18 +297,8 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
|
|
|
static void csiphy_stream_off(struct csiphy_device *csiphy)
|
|
|
{
|
|
|
u8 lane_mask = csiphy_get_lane_mask(&csiphy->cfg.csi2->lane_cfg);
|
|
|
- int i = 0;
|
|
|
|
|
|
- while (lane_mask) {
|
|
|
- if (lane_mask & 0x1)
|
|
|
- writel_relaxed(0x0, csiphy->base +
|
|
|
- CAMSS_CSI_PHY_LNn_CFG2(i));
|
|
|
-
|
|
|
- lane_mask >>= 1;
|
|
|
- i++;
|
|
|
- }
|
|
|
-
|
|
|
- writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_PWR_CFG);
|
|
|
+ csiphy->ops->lanes_disable(csiphy, lane_mask);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -696,6 +565,11 @@ int msm_csiphy_subdev_init(struct camss *camss,
|
|
|
csiphy->id = id;
|
|
|
csiphy->cfg.combo_mode = 0;
|
|
|
|
|
|
+ if (camss->version == CAMSS_8x16)
|
|
|
+ csiphy->ops = &csiphy_ops_2ph_1_0;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
/* Memory */
|
|
|
|
|
|
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
|
|
@@ -724,7 +598,8 @@ int msm_csiphy_subdev_init(struct camss *camss,
|
|
|
csiphy->irq = r->start;
|
|
|
snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d",
|
|
|
dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
|
|
|
- ret = devm_request_irq(dev, csiphy->irq, csiphy_isr,
|
|
|
+
|
|
|
+ ret = devm_request_irq(dev, csiphy->irq, csiphy->ops->isr,
|
|
|
IRQF_TRIGGER_RISING, csiphy->irq_name, csiphy);
|
|
|
if (ret < 0) {
|
|
|
dev_err(dev, "request_irq failed: %d\n", ret);
|