• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ispcsiphy.c
3  *
4  * TI OMAP3 ISP - CSI PHY module
5  *
6  * Copyright (C) 2010 Nokia Corporation
7  * Copyright (C) 2009 Texas Instruments, Inc.
8  *
9  * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10  *	     Sakari Ailus <sakari.ailus@iki.fi>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24  * 02110-1301 USA
25  */
26 
27 #include <linux/delay.h>
28 #include <linux/device.h>
29 #include <linux/regulator/consumer.h>
30 
31 #include "isp.h"
32 #include "ispreg.h"
33 #include "ispcsiphy.h"
34 
csiphy_routing_cfg_3630(struct isp_csiphy * phy,enum isp_interface_type iface,bool ccp2_strobe)35 static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
36 				    enum isp_interface_type iface,
37 				    bool ccp2_strobe)
38 {
39 	u32 reg = isp_reg_readl(
40 		phy->isp, OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0);
41 	u32 shift, mode;
42 
43 	switch (iface) {
44 	default:
45 	/* Should not happen in practice, but let's keep the compiler happy. */
46 	case ISP_INTERFACE_CCP2B_PHY1:
47 		reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
48 		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
49 		break;
50 	case ISP_INTERFACE_CSI2C_PHY1:
51 		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
52 		mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
53 		break;
54 	case ISP_INTERFACE_CCP2B_PHY2:
55 		reg |= OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
56 		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
57 		break;
58 	case ISP_INTERFACE_CSI2A_PHY2:
59 		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
60 		mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
61 		break;
62 	}
63 
64 	/* Select data/clock or data/strobe mode for CCP2 */
65 	if (iface == ISP_INTERFACE_CCP2B_PHY1 ||
66 	    iface == ISP_INTERFACE_CCP2B_PHY2) {
67 		if (ccp2_strobe)
68 			mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE;
69 		else
70 			mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_CLOCK;
71 	}
72 
73 	reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift);
74 	reg |= mode << shift;
75 
76 	isp_reg_writel(phy->isp, reg,
77 		       OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0);
78 }
79 
csiphy_routing_cfg_3430(struct isp_csiphy * phy,u32 iface,bool on,bool ccp2_strobe)80 static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
81 				    bool ccp2_strobe)
82 {
83 	u32 csirxfe = OMAP343X_CONTROL_CSIRXFE_PWRDNZ
84 		| OMAP343X_CONTROL_CSIRXFE_RESET;
85 
86 	/* Only the CCP2B on PHY1 is configurable. */
87 	if (iface != ISP_INTERFACE_CCP2B_PHY1)
88 		return;
89 
90 	if (!on) {
91 		isp_reg_writel(phy->isp, 0,
92 			       OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0);
93 		return;
94 	}
95 
96 	if (ccp2_strobe)
97 		csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM;
98 
99 	isp_reg_writel(phy->isp, csirxfe,
100 		       OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0);
101 }
102 
103 /*
104  * Configure OMAP 3 CSI PHY routing.
105  * @phy: relevant phy device
106  * @iface: ISP_INTERFACE_*
107  * @on: power on or off
108  * @ccp2_strobe: false: data/clock, true: data/strobe
109  *
110  * Note that the underlying routing configuration registers are part of the
111  * control (SCM) register space and part of the CORE power domain on both 3430
112  * and 3630, so they will not hold their contents in off-mode. This isn't an
113  * issue since the MPU power domain is forced on whilst the ISP is in use.
114  */
csiphy_routing_cfg(struct isp_csiphy * phy,enum isp_interface_type iface,bool on,bool ccp2_strobe)115 static void csiphy_routing_cfg(struct isp_csiphy *phy,
116 			       enum isp_interface_type iface, bool on,
117 			       bool ccp2_strobe)
118 {
119 	if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL]
120 	    && on)
121 		return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe);
122 	if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE])
123 		return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe);
124 }
125 
126 /*
127  * csiphy_power_autoswitch_enable
128  * @enable: Sets or clears the autoswitch function enable flag.
129  */
csiphy_power_autoswitch_enable(struct isp_csiphy * phy,bool enable)130 static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
131 {
132 	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
133 			ISPCSI2_PHY_CFG_PWR_AUTO,
134 			enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
135 }
136 
137 /*
138  * csiphy_set_power
139  * @power: Power state to be set.
140  *
141  * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
142  */
csiphy_set_power(struct isp_csiphy * phy,u32 power)143 static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
144 {
145 	u32 reg;
146 	u8 retry_count;
147 
148 	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
149 			ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
150 
151 	retry_count = 0;
152 	do {
153 		udelay(50);
154 		reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
155 				    ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
156 
157 		if (reg != power >> 2)
158 			retry_count++;
159 
160 	} while ((reg != power >> 2) && (retry_count < 100));
161 
162 	if (retry_count == 100) {
163 		dev_err(phy->isp->dev, "CSI2 CIO set power failed!\n");
164 		return -EBUSY;
165 	}
166 
167 	return 0;
168 }
169 
170 /*
171  * TCLK values are OK at their reset values
172  */
173 #define TCLK_TERM	0
174 #define TCLK_MISS	1
175 #define TCLK_SETTLE	14
176 
omap3isp_csiphy_config(struct isp_csiphy * phy)177 static int omap3isp_csiphy_config(struct isp_csiphy *phy)
178 {
179 	struct isp_csi2_device *csi2 = phy->csi2;
180 	struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
181 	struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv;
182 	struct isp_csiphy_lanes_cfg *lanes;
183 	int csi2_ddrclk_khz;
184 	unsigned int used_lanes = 0;
185 	unsigned int i;
186 	u32 reg;
187 
188 	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
189 	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
190 		lanes = &subdevs->bus.ccp2.lanecfg;
191 	else
192 		lanes = &subdevs->bus.csi2.lanecfg;
193 
194 	/* Clock and data lanes verification */
195 	for (i = 0; i < phy->num_data_lanes; i++) {
196 		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
197 			return -EINVAL;
198 
199 		if (used_lanes & (1 << lanes->data[i].pos))
200 			return -EINVAL;
201 
202 		used_lanes |= 1 << lanes->data[i].pos;
203 	}
204 
205 	if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
206 		return -EINVAL;
207 
208 	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
209 		return -EINVAL;
210 
211 	/*
212 	 * The PHY configuration is lost in off mode, that's not an
213 	 * issue since the MPU power domain is forced on whilst the
214 	 * ISP is in use.
215 	 */
216 	csiphy_routing_cfg(phy, subdevs->interface, true,
217 			   subdevs->bus.ccp2.phy_layer);
218 
219 	/* DPHY timing configuration */
220 	/* CSI-2 is DDR and we only count used lanes. */
221 	csi2_ddrclk_khz = pipe->external_rate / 1000
222 		/ (2 * hweight32(used_lanes)) * pipe->external_width;
223 
224 	reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG0);
225 
226 	reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
227 		 ISPCSIPHY_REG0_THS_SETTLE_MASK);
228 	/* THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. */
229 	reg |= (DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1)
230 		<< ISPCSIPHY_REG0_THS_TERM_SHIFT;
231 	/* THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. */
232 	reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3)
233 		<< ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
234 
235 	isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
236 
237 	reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG1);
238 
239 	reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
240 		 ISPCSIPHY_REG1_TCLK_MISS_MASK |
241 		 ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
242 	reg |= TCLK_TERM << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
243 	reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
244 	reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
245 
246 	isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
247 
248 	/* DPHY lane configuration */
249 	reg = isp_reg_readl(csi2->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
250 
251 	for (i = 0; i < phy->num_data_lanes; i++) {
252 		reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
253 			 ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
254 		reg |= (lanes->data[i].pol <<
255 			ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
256 		reg |= (lanes->data[i].pos <<
257 			ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
258 	}
259 
260 	reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
261 		 ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
262 	reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
263 	reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
264 
265 	isp_reg_writel(csi2->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
266 
267 	return 0;
268 }
269 
omap3isp_csiphy_acquire(struct isp_csiphy * phy)270 int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
271 {
272 	int rval;
273 
274 	if (phy->vdd == NULL) {
275 		dev_err(phy->isp->dev, "Power regulator for CSI PHY not "
276 			"available\n");
277 		return -ENODEV;
278 	}
279 
280 	mutex_lock(&phy->mutex);
281 
282 	rval = regulator_enable(phy->vdd);
283 	if (rval < 0)
284 		goto done;
285 
286 	rval = omap3isp_csi2_reset(phy->csi2);
287 	if (rval < 0)
288 		goto done;
289 
290 	rval = omap3isp_csiphy_config(phy);
291 	if (rval < 0)
292 		goto done;
293 
294 	rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
295 	if (rval) {
296 		regulator_disable(phy->vdd);
297 		goto done;
298 	}
299 
300 	csiphy_power_autoswitch_enable(phy, true);
301 	phy->phy_in_use = 1;
302 
303 done:
304 	mutex_unlock(&phy->mutex);
305 	return rval;
306 }
307 
omap3isp_csiphy_release(struct isp_csiphy * phy)308 void omap3isp_csiphy_release(struct isp_csiphy *phy)
309 {
310 	mutex_lock(&phy->mutex);
311 	if (phy->phy_in_use) {
312 		struct isp_csi2_device *csi2 = phy->csi2;
313 		struct isp_pipeline *pipe =
314 			to_isp_pipeline(&csi2->subdev.entity);
315 		struct isp_v4l2_subdevs_group *subdevs =
316 			pipe->external->host_priv;
317 
318 		csiphy_routing_cfg(phy, subdevs->interface, false,
319 				   subdevs->bus.ccp2.phy_layer);
320 		csiphy_power_autoswitch_enable(phy, false);
321 		csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
322 		regulator_disable(phy->vdd);
323 		phy->phy_in_use = 0;
324 	}
325 	mutex_unlock(&phy->mutex);
326 }
327 
328 /*
329  * omap3isp_csiphy_init - Initialize the CSI PHY frontends
330  */
omap3isp_csiphy_init(struct isp_device * isp)331 int omap3isp_csiphy_init(struct isp_device *isp)
332 {
333 	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
334 	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
335 
336 	phy2->isp = isp;
337 	phy2->csi2 = &isp->isp_csi2a;
338 	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
339 	phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
340 	phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
341 	mutex_init(&phy2->mutex);
342 
343 	if (isp->revision == ISP_REVISION_15_0) {
344 		phy1->isp = isp;
345 		phy1->csi2 = &isp->isp_csi2c;
346 		phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
347 		phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
348 		phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
349 		mutex_init(&phy1->mutex);
350 	}
351 
352 	return 0;
353 }
354