diff options
author | Sakari Ailus <sakari.ailus@iki.fi> | 2012-10-14 06:31:50 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-11-28 07:45:14 -0500 |
commit | a7b21061363dc980b3867a65d657ce7796303454 (patch) | |
tree | c6b4f10df6ef8c402623988ec95976a7dde727f0 /drivers/media/platform/omap3isp | |
parent | ec51e960bc355c5ebf7501f1e74723d5d4f4212d (diff) |
[media] omap3isp: Configure CSI-2 phy based on platform data
Configure CSI-2 phy based on platform data in the ISP driver. For that, the
new V4L2_CID_IMAGE_SOURCE_PIXEL_RATE control is used. Previously the same
was configured from the board code.
Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/platform/omap3isp')
-rw-r--r-- | drivers/media/platform/omap3isp/isp.h | 3 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/ispcsiphy.c | 153 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/ispcsiphy.h | 10 |
3 files changed, 83 insertions, 83 deletions
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 6fed2228e780..accb3b04f5dc 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h | |||
@@ -129,9 +129,6 @@ struct isp_reg { | |||
129 | 129 | ||
130 | struct isp_platform_callback { | 130 | struct isp_platform_callback { |
131 | u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); | 131 | u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); |
132 | int (*csiphy_config)(struct isp_csiphy *phy, | ||
133 | struct isp_csiphy_dphy_cfg *dphy, | ||
134 | struct isp_csiphy_lanes_cfg *lanes); | ||
135 | }; | 132 | }; |
136 | 133 | ||
137 | /* | 134 | /* |
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index 8ac99b9dc053..d6eb4f9655fe 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c | |||
@@ -121,36 +121,6 @@ static void csiphy_routing_cfg(struct isp_csiphy *phy, u32 iface, bool on, | |||
121 | } | 121 | } |
122 | 122 | ||
123 | /* | 123 | /* |
124 | * csiphy_lanes_config - Configuration of CSIPHY lanes. | ||
125 | * | ||
126 | * Updates HW configuration. | ||
127 | * Called with phy->mutex taken. | ||
128 | */ | ||
129 | static void csiphy_lanes_config(struct isp_csiphy *phy) | ||
130 | { | ||
131 | unsigned int i; | ||
132 | u32 reg; | ||
133 | |||
134 | reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); | ||
135 | |||
136 | for (i = 0; i < phy->num_data_lanes; i++) { | ||
137 | reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | | ||
138 | ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); | ||
139 | reg |= (phy->lanes.data[i].pol << | ||
140 | ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); | ||
141 | reg |= (phy->lanes.data[i].pos << | ||
142 | ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); | ||
143 | } | ||
144 | |||
145 | reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | | ||
146 | ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); | ||
147 | reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; | ||
148 | reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; | ||
149 | |||
150 | isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * csiphy_power_autoswitch_enable | 124 | * csiphy_power_autoswitch_enable |
155 | * @enable: Sets or clears the autoswitch function enable flag. | 125 | * @enable: Sets or clears the autoswitch function enable flag. |
156 | */ | 126 | */ |
@@ -195,43 +165,28 @@ static int csiphy_set_power(struct isp_csiphy *phy, u32 power) | |||
195 | } | 165 | } |
196 | 166 | ||
197 | /* | 167 | /* |
198 | * csiphy_dphy_config - Configure CSI2 D-PHY parameters. | 168 | * TCLK values are OK at their reset values |
199 | * | ||
200 | * Called with phy->mutex taken. | ||
201 | */ | 169 | */ |
202 | static void csiphy_dphy_config(struct isp_csiphy *phy) | 170 | #define TCLK_TERM 0 |
203 | { | 171 | #define TCLK_MISS 1 |
204 | u32 reg; | 172 | #define TCLK_SETTLE 14 |
205 | |||
206 | /* Set up ISPCSIPHY_REG0 */ | ||
207 | reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); | ||
208 | |||
209 | reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | | ||
210 | ISPCSIPHY_REG0_THS_SETTLE_MASK); | ||
211 | reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT; | ||
212 | reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; | ||
213 | |||
214 | isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); | ||
215 | |||
216 | /* Set up ISPCSIPHY_REG1 */ | ||
217 | reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); | ||
218 | |||
219 | reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | | ||
220 | ISPCSIPHY_REG1_TCLK_MISS_MASK | | ||
221 | ISPCSIPHY_REG1_TCLK_SETTLE_MASK); | ||
222 | reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; | ||
223 | reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; | ||
224 | reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; | ||
225 | 173 | ||
226 | isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); | 174 | static int omap3isp_csiphy_config(struct isp_csiphy *phy) |
227 | } | ||
228 | |||
229 | static int csiphy_config(struct isp_csiphy *phy, | ||
230 | struct isp_csiphy_dphy_cfg *dphy, | ||
231 | struct isp_csiphy_lanes_cfg *lanes) | ||
232 | { | 175 | { |
176 | struct isp_csi2_device *csi2 = phy->csi2; | ||
177 | struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); | ||
178 | struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv; | ||
179 | struct isp_csiphy_lanes_cfg *lanes; | ||
180 | int csi2_ddrclk_khz; | ||
233 | unsigned int used_lanes = 0; | 181 | unsigned int used_lanes = 0; |
234 | unsigned int i; | 182 | unsigned int i; |
183 | u32 reg; | ||
184 | |||
185 | if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1 | ||
186 | || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2) | ||
187 | lanes = &subdevs->bus.ccp2.lanecfg; | ||
188 | else | ||
189 | lanes = &subdevs->bus.csi2.lanecfg; | ||
235 | 190 | ||
236 | /* Clock and data lanes verification */ | 191 | /* Clock and data lanes verification */ |
237 | for (i = 0; i < phy->num_data_lanes; i++) { | 192 | for (i = 0; i < phy->num_data_lanes; i++) { |
@@ -250,10 +205,61 @@ static int csiphy_config(struct isp_csiphy *phy, | |||
250 | if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) | 205 | if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) |
251 | return -EINVAL; | 206 | return -EINVAL; |
252 | 207 | ||
253 | mutex_lock(&phy->mutex); | 208 | /* |
254 | phy->dphy = *dphy; | 209 | * The PHY configuration is lost in off mode, that's not an |
255 | phy->lanes = *lanes; | 210 | * issue since the MPU power domain is forced on whilst the |
256 | mutex_unlock(&phy->mutex); | 211 | * ISP is in use. |
212 | */ | ||
213 | csiphy_routing_cfg(phy, subdevs->interface, true, | ||
214 | subdevs->bus.ccp2.phy_layer); | ||
215 | |||
216 | /* DPHY timing configuration */ | ||
217 | /* CSI-2 is DDR and we only count used lanes. */ | ||
218 | csi2_ddrclk_khz = pipe->external_rate / 1000 | ||
219 | / (2 * hweight32(used_lanes)) * pipe->external_width; | ||
220 | |||
221 | reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG0); | ||
222 | |||
223 | reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | | ||
224 | ISPCSIPHY_REG0_THS_SETTLE_MASK); | ||
225 | /* THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. */ | ||
226 | reg |= (DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1) | ||
227 | << ISPCSIPHY_REG0_THS_TERM_SHIFT; | ||
228 | /* THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. */ | ||
229 | reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3) | ||
230 | << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; | ||
231 | |||
232 | isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); | ||
233 | |||
234 | reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG1); | ||
235 | |||
236 | reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | | ||
237 | ISPCSIPHY_REG1_TCLK_MISS_MASK | | ||
238 | ISPCSIPHY_REG1_TCLK_SETTLE_MASK); | ||
239 | reg |= TCLK_TERM << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; | ||
240 | reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; | ||
241 | reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; | ||
242 | |||
243 | isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); | ||
244 | |||
245 | /* DPHY lane configuration */ | ||
246 | reg = isp_reg_readl(csi2->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); | ||
247 | |||
248 | for (i = 0; i < phy->num_data_lanes; i++) { | ||
249 | reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | | ||
250 | ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); | ||
251 | reg |= (lanes->data[i].pol << | ||
252 | ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); | ||
253 | reg |= (lanes->data[i].pos << | ||
254 | ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); | ||
255 | } | ||
256 | |||
257 | reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | | ||
258 | ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); | ||
259 | reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; | ||
260 | reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; | ||
261 | |||
262 | isp_reg_writel(csi2->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); | ||
257 | 263 | ||
258 | return 0; | 264 | return 0; |
259 | } | 265 | } |
@@ -278,8 +284,9 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy) | |||
278 | if (rval < 0) | 284 | if (rval < 0) |
279 | goto done; | 285 | goto done; |
280 | 286 | ||
281 | csiphy_dphy_config(phy); | 287 | rval = omap3isp_csiphy_config(phy); |
282 | csiphy_lanes_config(phy); | 288 | if (rval < 0) |
289 | goto done; | ||
283 | 290 | ||
284 | rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); | 291 | rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); |
285 | if (rval) { | 292 | if (rval) { |
@@ -299,6 +306,14 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy) | |||
299 | { | 306 | { |
300 | mutex_lock(&phy->mutex); | 307 | mutex_lock(&phy->mutex); |
301 | if (phy->phy_in_use) { | 308 | if (phy->phy_in_use) { |
309 | struct isp_csi2_device *csi2 = phy->csi2; | ||
310 | struct isp_pipeline *pipe = | ||
311 | to_isp_pipeline(&csi2->subdev.entity); | ||
312 | struct isp_v4l2_subdevs_group *subdevs = | ||
313 | pipe->external->host_priv; | ||
314 | |||
315 | csiphy_routing_cfg(phy, subdevs->interface, false, | ||
316 | subdevs->bus.ccp2.phy_layer); | ||
302 | csiphy_power_autoswitch_enable(phy, false); | 317 | csiphy_power_autoswitch_enable(phy, false); |
303 | csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); | 318 | csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); |
304 | regulator_disable(phy->vdd); | 319 | regulator_disable(phy->vdd); |
@@ -315,8 +330,6 @@ int omap3isp_csiphy_init(struct isp_device *isp) | |||
315 | struct isp_csiphy *phy1 = &isp->isp_csiphy1; | 330 | struct isp_csiphy *phy1 = &isp->isp_csiphy1; |
316 | struct isp_csiphy *phy2 = &isp->isp_csiphy2; | 331 | struct isp_csiphy *phy2 = &isp->isp_csiphy2; |
317 | 332 | ||
318 | isp->platform_cb.csiphy_config = csiphy_config; | ||
319 | |||
320 | phy2->isp = isp; | 333 | phy2->isp = isp; |
321 | phy2->csi2 = &isp->isp_csi2a; | 334 | phy2->csi2 = &isp->isp_csi2a; |
322 | phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; | 335 | phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; |
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index e93a661e65d9..14551fd77697 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h | |||
@@ -32,14 +32,6 @@ | |||
32 | struct isp_csi2_device; | 32 | struct isp_csi2_device; |
33 | struct regulator; | 33 | struct regulator; |
34 | 34 | ||
35 | struct isp_csiphy_dphy_cfg { | ||
36 | u8 ths_term; | ||
37 | u8 ths_settle; | ||
38 | u8 tclk_term; | ||
39 | unsigned tclk_miss:1; | ||
40 | u8 tclk_settle; | ||
41 | }; | ||
42 | |||
43 | struct isp_csiphy { | 35 | struct isp_csiphy { |
44 | struct isp_device *isp; | 36 | struct isp_device *isp; |
45 | struct mutex mutex; /* serialize csiphy configuration */ | 37 | struct mutex mutex; /* serialize csiphy configuration */ |
@@ -52,8 +44,6 @@ struct isp_csiphy { | |||
52 | unsigned int phy_regs; | 44 | unsigned int phy_regs; |
53 | 45 | ||
54 | u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ | 46 | u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ |
55 | struct isp_csiphy_lanes_cfg lanes; | ||
56 | struct isp_csiphy_dphy_cfg dphy; | ||
57 | }; | 47 | }; |
58 | 48 | ||
59 | int omap3isp_csiphy_acquire(struct isp_csiphy *phy); | 49 | int omap3isp_csiphy_acquire(struct isp_csiphy *phy); |