Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: camss: use v4l2_get_link_freq() to calculate the relevant clocks

There are places in the camss driver where camss_get_pixel_clock() is
called to get the pixel rate (using V4L2_CID_PIXEL_RATE control) and to
calculate the link frequency from it. There is a case when this would
not work: when V4L2_CID_PIXEL_RATE gets the rate at which the pixels are
read (sampled) from the sensor's pixel array, and this rate is different
from the pixel transmission rate over the CSI link, the link frequency
value can't be calculated from the pixel rate. One needs to use
V4L2_CID_LINK_FREQ to get the link frequency in this case.

Replace such calls to camss_get_pixel_clock() with calls to a wrapper
around v4l2_get_link_freq(). v4l2_get_link_freq() tries V4L2_CID_LINK_FREQ
first, and if it is not implemented by the camera sensor driver, falls
back to V4L2_CID_PIXEL_RATE to calculate the link frequency value from.

Calls to camss_get_pixel_clock() from vfe_[check,set]_clock_rates()
are left intact as it looks like this VFE clock does depend on the
rate the pixel samples comes out of the camera sensor, not on the
frequency at which the link between the sensor and the CSI receiver
operates.

Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
Acked-by: Robert Foss <robert.foss@linaro.org>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Andrey Konovalov and committed by
Mauro Carvalho Chehab
78c2cc28 67012d97

+71 -56
+9 -11
drivers/media/platform/qcom/camss/camss-csid.c
··· 462 462 static int csid_set_clock_rates(struct csid_device *csid) 463 463 { 464 464 struct device *dev = csid->camss->dev; 465 - u32 pixel_clock; 465 + const struct csid_format *fmt; 466 + s64 link_freq; 466 467 int i, j; 467 468 int ret; 468 469 469 - ret = camss_get_pixel_clock(&csid->subdev.entity, &pixel_clock); 470 - if (ret) 471 - pixel_clock = 0; 470 + fmt = csid_get_fmt_entry(csid->formats, csid->nformats, 471 + csid->fmt[MSM_CSIPHY_PAD_SINK].code); 472 + link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, 473 + csid->phy.lane_cnt); 474 + if (link_freq < 0) 475 + link_freq = 0; 472 476 473 477 for (i = 0; i < csid->nclocks; i++) { 474 478 struct camss_clock *clock = &csid->clock[i]; ··· 481 477 !strcmp(clock->name, "csi1") || 482 478 !strcmp(clock->name, "csi2") || 483 479 !strcmp(clock->name, "csi3")) { 484 - const struct csid_format *f = csid_get_fmt_entry( 485 - csid->formats, 486 - csid->nformats, 487 - csid->fmt[MSM_CSIPHY_PAD_SINK].code); 488 - u8 num_lanes = csid->phy.lane_cnt; 489 - u64 min_rate = pixel_clock * f->bpp / 490 - (2 * num_lanes * 4); 480 + u64 min_rate = link_freq / 4; 491 481 long rate; 492 482 493 483 camss_add_clock_margin(&min_rate);
+10 -12
drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c
··· 51 51 * 52 52 * Helper function to calculate settle count value. This is 53 53 * based on the CSI2 T_hs_settle parameter which in turn 54 - * is calculated based on the CSI2 transmitter pixel clock 55 - * frequency. 54 + * is calculated based on the CSI2 transmitter link frequency. 56 55 * 57 - * Return settle count value or 0 if the CSI2 pixel clock 58 - * frequency is not available 56 + * Return settle count value or 0 if the CSI2 link frequency 57 + * is not available 59 58 */ 60 - static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, 61 - u32 timer_clk_rate) 59 + static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate) 62 60 { 63 - u32 mipi_clock; /* Hz */ 64 61 u32 ui; /* ps */ 65 62 u32 timer_period; /* ps */ 66 63 u32 t_hs_prepare_max; /* ps */ ··· 65 68 u32 t_hs_settle; /* ps */ 66 69 u8 settle_cnt; 67 70 68 - mipi_clock = pixel_clock * bpp / (2 * num_lanes); 69 - ui = div_u64(1000000000000LL, mipi_clock); 71 + if (link_freq <= 0) 72 + return 0; 73 + 74 + ui = div_u64(1000000000000LL, link_freq); 70 75 ui /= 2; 71 76 t_hs_prepare_max = 85000 + 6 * ui; 72 77 t_hs_prepare_zero_min = 145000 + 10 * ui; ··· 82 83 83 84 static void csiphy_lanes_enable(struct csiphy_device *csiphy, 84 85 struct csiphy_config *cfg, 85 - u32 pixel_clock, u8 bpp, u8 lane_mask) 86 + s64 link_freq, u8 lane_mask) 86 87 { 87 88 struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; 88 89 u8 settle_cnt; 89 90 u8 val, l = 0; 90 91 int i = 0; 91 92 92 - settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data, 93 - csiphy->timer_clk_rate); 93 + settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); 94 94 95 95 writel_relaxed(0x1, csiphy->base + 96 96 CAMSS_CSI_PHY_GLBL_T_INIT_CFG0);
+10 -12
drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
··· 107 107 * 108 108 * Helper function to calculate settle count value. This is 109 109 * based on the CSI2 T_hs_settle parameter which in turn 110 - * is calculated based on the CSI2 transmitter pixel clock 111 - * frequency. 110 + * is calculated based on the CSI2 transmitter link frequency. 112 111 * 113 - * Return settle count value or 0 if the CSI2 pixel clock 114 - * frequency is not available 112 + * Return settle count value or 0 if the CSI2 link frequency 113 + * is not available 115 114 */ 116 - static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, 117 - u32 timer_clk_rate) 115 + static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate) 118 116 { 119 - u32 mipi_clock; /* Hz */ 120 117 u32 ui; /* ps */ 121 118 u32 timer_period; /* ps */ 122 119 u32 t_hs_prepare_max; /* ps */ 123 120 u32 t_hs_settle; /* ps */ 124 121 u8 settle_cnt; 125 122 126 - mipi_clock = pixel_clock * bpp / (2 * num_lanes); 127 - ui = div_u64(1000000000000LL, mipi_clock); 123 + if (link_freq <= 0) 124 + return 0; 125 + 126 + ui = div_u64(1000000000000LL, link_freq); 128 127 ui /= 2; 129 128 t_hs_prepare_max = 85000 + 6 * ui; 130 129 t_hs_settle = t_hs_prepare_max; ··· 136 137 137 138 static void csiphy_lanes_enable(struct csiphy_device *csiphy, 138 139 struct csiphy_config *cfg, 139 - u32 pixel_clock, u8 bpp, u8 lane_mask) 140 + s64 link_freq, u8 lane_mask) 140 141 { 141 142 struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; 142 143 u8 settle_cnt; 143 144 u8 val, l = 0; 144 145 int i; 145 146 146 - settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data, 147 - csiphy->timer_clk_rate); 147 + settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); 148 148 149 149 val = BIT(c->clk.pos); 150 150 for (i = 0; i < c->num_data; i++)
+16 -20
drivers/media/platform/qcom/camss/camss-csiphy.c
··· 102 102 static int csiphy_set_clock_rates(struct csiphy_device *csiphy) 103 103 { 104 104 struct device *dev = csiphy->camss->dev; 105 - u32 pixel_clock; 105 + s64 link_freq; 106 106 int i, j; 107 107 int ret; 108 108 109 - ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); 110 - if (ret) 111 - pixel_clock = 0; 109 + u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, 110 + csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); 111 + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; 112 + 113 + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); 114 + if (link_freq < 0) 115 + link_freq = 0; 112 116 113 117 for (i = 0; i < csiphy->nclocks; i++) { 114 118 struct camss_clock *clock = &csiphy->clock[i]; 115 119 116 120 if (csiphy->rate_set[i]) { 117 - u8 bpp = csiphy_get_bpp(csiphy->formats, 118 - csiphy->nformats, 119 - csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); 120 - u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; 121 - u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); 121 + u64 min_rate = link_freq / 4; 122 122 long round_rate; 123 123 124 124 camss_add_clock_margin(&min_rate); ··· 238 238 static int csiphy_stream_on(struct csiphy_device *csiphy) 239 239 { 240 240 struct csiphy_config *cfg = &csiphy->cfg; 241 - u32 pixel_clock; 241 + s64 link_freq; 242 242 u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg); 243 243 u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, 244 244 csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); 245 + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; 245 246 u8 val; 246 - int ret; 247 247 248 - ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); 249 - if (ret) { 248 + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); 249 + 250 + if (link_freq < 0) { 250 251 dev_err(csiphy->camss->dev, 251 - "Cannot get CSI2 transmitter's pixel clock\n"); 252 - return -EINVAL; 253 - } 254 - if (!pixel_clock) { 255 - dev_err(csiphy->camss->dev, 256 - "Got pixel clock == 0, cannot continue\n"); 252 + "Cannot get CSI2 transmitter's link frequency\n"); 257 253 return -EINVAL; 258 254 } 259 255 ··· 264 268 writel_relaxed(val, csiphy->base_clk_mux); 265 269 wmb(); 266 270 267 - csiphy->ops->lanes_enable(csiphy, cfg, pixel_clock, bpp, lane_mask); 271 + csiphy->ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); 268 272 269 273 return 0; 270 274 }
+1 -1
drivers/media/platform/qcom/camss/camss-csiphy.h
··· 50 50 void (*reset)(struct csiphy_device *csiphy); 51 51 void (*lanes_enable)(struct csiphy_device *csiphy, 52 52 struct csiphy_config *cfg, 53 - u32 pixel_clock, u8 bpp, u8 lane_mask); 53 + s64 link_freq, u8 lane_mask); 54 54 void (*lanes_disable)(struct csiphy_device *csiphy, 55 55 struct csiphy_config *cfg); 56 56 irqreturn_t (*isr)(int irq, void *dev);
+23
drivers/media/platform/qcom/camss/camss.c
··· 548 548 } 549 549 } 550 550 551 + /** 552 + * camss_get_link_freq - Get link frequency from sensor 553 + * @entity: Media entity in the current pipeline 554 + * @bpp: Number of bits per pixel for the current format 555 + * @lanes: Number of lanes in the link to the sensor 556 + * 557 + * Return link frequency on success or a negative error code otherwise 558 + */ 559 + s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, 560 + unsigned int lanes) 561 + { 562 + struct media_entity *sensor; 563 + struct v4l2_subdev *subdev; 564 + 565 + sensor = camss_find_sensor(entity); 566 + if (!sensor) 567 + return -ENODEV; 568 + 569 + subdev = media_entity_to_v4l2_subdev(sensor); 570 + 571 + return v4l2_get_link_freq(subdev->ctrl_handler, bpp, 2 * lanes); 572 + } 573 + 551 574 /* 552 575 * camss_get_pixel_clock - Get pixel clock rate from sensor 553 576 * @entity: Media entity in the current pipeline
+2
drivers/media/platform/qcom/camss/camss.h
··· 108 108 struct device *dev); 109 109 void camss_disable_clocks(int nclocks, struct camss_clock *clock); 110 110 struct media_entity *camss_find_sensor(struct media_entity *entity); 111 + s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, 112 + unsigned int lanes); 111 113 int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock); 112 114 int camss_pm_domain_on(struct camss *camss, int id); 113 115 void camss_pm_domain_off(struct camss *camss, int id);