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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9-rc3 353 lines 10 kB view raw
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 35static 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 80static 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 */ 115static 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 */ 130static 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 */ 143static 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 177static 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 270int 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 303done: 304 mutex_unlock(&phy->mutex); 305 return rval; 306} 307 308void 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 */ 331int 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}