root/drivers/media/platform/omap3isp/ispcsiphy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. csiphy_routing_cfg_3630
  2. csiphy_routing_cfg_3430
  3. csiphy_routing_cfg
  4. csiphy_power_autoswitch_enable
  5. csiphy_set_power
  6. omap3isp_csiphy_config
  7. omap3isp_csiphy_acquire
  8. omap3isp_csiphy_release
  9. omap3isp_csiphy_init
  10. omap3isp_csiphy_cleanup

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

/* [<][>][^][v][top][bottom][index][help] */