1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2013 NVIDIA Corporation 4 * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com> 5 */ 6 7#include <dm.h> 8#include <clk.h> 9#include <misc.h> 10#include <linux/delay.h> 11#include <linux/iopoll.h> 12 13#include <asm/io.h> 14 15/* MIPI control registers 0x00 ~ 0x60 */ 16struct mipi_ctlr { 17 uint mipi_cal_ctrl; 18 uint mipi_cal_autocal_ctrl; 19 uint mipi_cal_status; 20 21 uint unused1[2]; 22 23 uint mipi_cal_config_csia; 24 uint mipi_cal_config_csib; 25 uint mipi_cal_config_csic; 26 uint mipi_cal_config_csid; 27 uint mipi_cal_config_csie; 28 29 uint unused2[4]; 30 31 uint mipi_cal_config_dsia; 32 uint mipi_cal_config_dsib; 33 uint mipi_cal_config_dsic; 34 uint mipi_cal_config_dsid; 35 36 uint unused3[4]; 37 38 uint mipi_cal_bias_pad_cfg0; 39 uint mipi_cal_bias_pad_cfg1; 40 uint mipi_cal_bias_pad_cfg2; 41}; 42 43#define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26) 44#define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24) 45#define MIPI_CAL_CTRL_CLKEN_OVR BIT(4) 46#define MIPI_CAL_CTRL_START BIT(0) 47 48#define MIPI_CAL_STATUS_DONE BIT(16) 49#define MIPI_CAL_STATUS_ACTIVE BIT(0) 50 51#define MIPI_CAL_OVERIDE(x) (((x) & 0x1) << 30) 52#define MIPI_CAL_SEL(x) (((x) & 0x1) << 21) 53#define MIPI_CAL_HSPDOS(x) (((x) & 0x1f) << 16) 54#define MIPI_CAL_HSPUOS(x) (((x) & 0x1f) << 8) 55#define MIPI_CAL_TERMOS(x) (((x) & 0x1f) << 0) 56 57#define MIPI_CAL_BIAS_PAD_PDVCLAMP BIT(1) 58#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF BIT(0) 59 60#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) 61#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8) 62 63#define MIPI_CAL_BIAS_PAD_VCLAMP(x) (((x) & 0x7) << 16) 64#define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4) 65#define MIPI_CAL_BIAS_PAD_PDVREG BIT(1) 66 67struct tegra_mipi_priv { 68 struct mipi_ctlr *mipi; 69 struct clk *mipi_cal; 70}; 71 72static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf, 73 int size) 74{ 75 struct tegra_mipi_priv *priv = dev_get_priv(dev); 76 u32 value; 77 78 value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) | 79 MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0); 80 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1); 81 82 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); 83 value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); 84 value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); 85 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); 86 87 value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) | 88 MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x4) | 89 MIPI_CAL_TERMOS(0x5); 90 writel(value, &priv->mipi->mipi_cal_config_dsia); 91 writel(value, &priv->mipi->mipi_cal_config_dsib); 92 93 /* Deselect PAD C */ 94 value = readl(&priv->mipi->mipi_cal_config_dsic); 95 value &= ~(MIPI_CAL_SEL(0x1)); 96 writel(value, &priv->mipi->mipi_cal_config_dsic); 97 98 /* Deselect PAD D */ 99 value = readl(&priv->mipi->mipi_cal_config_dsid); 100 value &= ~(MIPI_CAL_SEL(0x1)); 101 writel(value, &priv->mipi->mipi_cal_config_dsid); 102 103 value = readl(&priv->mipi->mipi_cal_ctrl); 104 value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf); 105 value &= ~MIPI_CAL_CTRL_PRESCALE(0x3); 106 value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa) | 107 MIPI_CAL_CTRL_PRESCALE(0x2) | 108 MIPI_CAL_CTRL_CLKEN_OVR; 109 writel(value, &priv->mipi->mipi_cal_ctrl); 110 111 /* clear any pending status bits */ 112 value = readl(&priv->mipi->mipi_cal_status); 113 writel(value, &priv->mipi->mipi_cal_status); 114 115 value = readl(&priv->mipi->mipi_cal_ctrl); 116 value |= MIPI_CAL_CTRL_START; 117 writel(value, &priv->mipi->mipi_cal_ctrl); 118 119 /* 120 * Wait for min 72uS to let calibration logic finish calibration 121 * sequence codes before waiting for pads idle state to apply the 122 * results. 123 */ 124 udelay(80); 125 126 return readl_poll_sleep_timeout(&priv->mipi->mipi_cal_status, value, 127 !(value & MIPI_CAL_STATUS_ACTIVE) && 128 (value & MIPI_CAL_STATUS_DONE), 100, 129 250000); 130} 131 132static int tegra_mipi_enable(struct udevice *dev, bool val) 133{ 134 struct tegra_mipi_priv *priv = dev_get_priv(dev); 135 u32 value; 136 137 clk_enable(priv->mipi_cal); 138 139 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg0); 140 value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; 141 value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; 142 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg0); 143 144 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); 145 value &= ~MIPI_CAL_BIAS_PAD_PDVREG; 146 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); 147 148 return 0; 149} 150 151static const struct misc_ops tegra_mipi_ops = { 152 .write = tegra_mipi_calibrate, 153 .set_enabled = tegra_mipi_enable, 154}; 155 156static int tegra_mipi_probe(struct udevice *dev) 157{ 158 struct tegra_mipi_priv *priv = dev_get_priv(dev); 159 160 priv->mipi = (struct mipi_ctlr *)dev_read_addr_ptr(dev); 161 if (!priv->mipi) { 162 log_debug("%s: no MIPI controller address\n", __func__); 163 return -EINVAL; 164 } 165 166 priv->mipi_cal = devm_clk_get(dev, NULL); 167 if (IS_ERR(priv->mipi_cal)) { 168 log_debug("%s: Could not get MIPI clock: %ld\n", 169 __func__, PTR_ERR(priv->mipi_cal)); 170 return PTR_ERR(priv->mipi_cal); 171 } 172 173 return 0; 174} 175 176static const struct udevice_id tegra_mipi_ids[] = { 177 { .compatible = "nvidia,tegra114-mipi" }, 178 { } 179}; 180 181U_BOOT_DRIVER(tegra_mipi) = { 182 .name = "tegra_mipi", 183 .id = UCLASS_MISC, 184 .ops = &tegra_mipi_ops, 185 .of_match = tegra_mipi_ids, 186 .probe = tegra_mipi_probe, 187 .priv_auto = sizeof(struct tegra_mipi_priv), 188}; 189