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.

gpu: host1x: convert MIPI to use operation function pointers

Convert existing MIPI code to use operation function pointers, a necessary
step for supporting Tegra20/Tegra30 SoCs. All common MIPI configuration
that is SoC-independent remains in mipi.c, while all SoC-specific code is
moved to tegra114-mipi.c (The naming matches the first SoC generation with
a dedicated calibration block). Shared structures and function calls are
placed into tegra-mipi-cal.h.

Tested-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # tegra20, parallel camera
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Acked-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>

authored by

Svyatoslav Ryhel and committed by
Hans Verkuil
c888c4c8 6926495f

+676 -489
+1
drivers/gpu/drm/tegra/dsi.c
··· 14 14 #include <linux/pm_runtime.h> 15 15 #include <linux/regulator/consumer.h> 16 16 #include <linux/reset.h> 17 + #include <linux/tegra-mipi-cal.h> 17 18 18 19 #include <video/mipi_display.h> 19 20
+1
drivers/gpu/host1x/Makefile
··· 9 9 job.o \ 10 10 debug.o \ 11 11 mipi.o \ 12 + tegra114-mipi.o \ 12 13 fence.o \ 13 14 hw/host1x01.o \ 14 15 hw/host1x02.o \
+133 -479
drivers/gpu/host1x/mipi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 2 3 * Copyright (C) 2013 NVIDIA Corporation 3 - * 4 - * Permission to use, copy, modify, distribute, and sell this software and its 5 - * documentation for any purpose is hereby granted without fee, provided that 6 - * the above copyright notice appear in all copies and that both that copyright 7 - * notice and this permission notice appear in supporting documentation, and 8 - * that the name of the copyright holders not be used in advertising or 9 - * publicity pertaining to distribution of the software without specific, 10 - * written prior permission. The copyright holders make no representations 11 - * about the suitability of this software for any purpose. It is provided "as 12 - * is" without express or implied warranty. 13 - * 14 - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 - * OF THIS SOFTWARE. 4 + * Copyright (C) 2025 Svyatoslav Ryhel <clamor95@gmail.com> 21 5 */ 22 6 23 7 #include <linux/clk.h> 24 - #include <linux/host1x.h> 25 8 #include <linux/io.h> 26 9 #include <linux/iopoll.h> 10 + #include <linux/module.h> 11 + #include <linux/of.h> 27 12 #include <linux/of_platform.h> 28 13 #include <linux/platform_device.h> 29 14 #include <linux/slab.h> 15 + #include <linux/tegra-mipi-cal.h> 30 16 31 - #include "dev.h" 17 + /* only need to support one provider */ 18 + static struct { 19 + struct device_node *np; 20 + const struct tegra_mipi_ops *ops; 21 + } provider; 32 22 33 - #define MIPI_CAL_CTRL 0x00 34 - #define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26) 35 - #define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24) 36 - #define MIPI_CAL_CTRL_CLKEN_OVR (1 << 4) 37 - #define MIPI_CAL_CTRL_START (1 << 0) 38 - 39 - #define MIPI_CAL_AUTOCAL_CTRL 0x01 40 - 41 - #define MIPI_CAL_STATUS 0x02 42 - #define MIPI_CAL_STATUS_DONE (1 << 16) 43 - #define MIPI_CAL_STATUS_ACTIVE (1 << 0) 44 - 45 - #define MIPI_CAL_CONFIG_CSIA 0x05 46 - #define MIPI_CAL_CONFIG_CSIB 0x06 47 - #define MIPI_CAL_CONFIG_CSIC 0x07 48 - #define MIPI_CAL_CONFIG_CSID 0x08 49 - #define MIPI_CAL_CONFIG_CSIE 0x09 50 - #define MIPI_CAL_CONFIG_CSIF 0x0a 51 - #define MIPI_CAL_CONFIG_DSIA 0x0e 52 - #define MIPI_CAL_CONFIG_DSIB 0x0f 53 - #define MIPI_CAL_CONFIG_DSIC 0x10 54 - #define MIPI_CAL_CONFIG_DSID 0x11 55 - 56 - #define MIPI_CAL_CONFIG_DSIA_CLK 0x19 57 - #define MIPI_CAL_CONFIG_DSIB_CLK 0x1a 58 - #define MIPI_CAL_CONFIG_CSIAB_CLK 0x1b 59 - #define MIPI_CAL_CONFIG_DSIC_CLK 0x1c 60 - #define MIPI_CAL_CONFIG_CSICD_CLK 0x1c 61 - #define MIPI_CAL_CONFIG_DSID_CLK 0x1d 62 - #define MIPI_CAL_CONFIG_CSIE_CLK 0x1d 63 - 64 - /* for data and clock lanes */ 65 - #define MIPI_CAL_CONFIG_SELECT (1 << 21) 66 - 67 - /* for data lanes */ 68 - #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) 69 - #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) 70 - #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) 71 - 72 - /* for clock lanes */ 73 - #define MIPI_CAL_CONFIG_HSCLKPDOSD(x) (((x) & 0x1f) << 8) 74 - #define MIPI_CAL_CONFIG_HSCLKPUOSD(x) (((x) & 0x1f) << 0) 75 - 76 - #define MIPI_CAL_BIAS_PAD_CFG0 0x16 77 - #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) 78 - #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) 79 - 80 - #define MIPI_CAL_BIAS_PAD_CFG1 0x17 81 - #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) 82 - #define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8) 83 - 84 - #define MIPI_CAL_BIAS_PAD_CFG2 0x18 85 - #define MIPI_CAL_BIAS_PAD_VCLAMP(x) (((x) & 0x7) << 16) 86 - #define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4) 87 - #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) 88 - 89 - struct tegra_mipi_pad { 90 - unsigned long data; 91 - unsigned long clk; 92 - }; 93 - 94 - struct tegra_mipi_soc { 95 - bool has_clk_lane; 96 - const struct tegra_mipi_pad *pads; 97 - unsigned int num_pads; 98 - 99 - bool clock_enable_override; 100 - bool needs_vclamp_ref; 101 - 102 - /* bias pad configuration settings */ 103 - u8 pad_drive_down_ref; 104 - u8 pad_drive_up_ref; 105 - 106 - u8 pad_vclamp_level; 107 - u8 pad_vauxp_level; 108 - 109 - /* calibration settings for data lanes */ 110 - u8 hspdos; 111 - u8 hspuos; 112 - u8 termos; 113 - 114 - /* calibration settings for clock lanes */ 115 - u8 hsclkpdos; 116 - u8 hsclkpuos; 117 - }; 118 - 119 - struct tegra_mipi { 120 - const struct tegra_mipi_soc *soc; 121 - struct device *dev; 122 - void __iomem *regs; 123 - struct mutex lock; 124 - struct clk *clk; 125 - 126 - unsigned long usage_count; 127 - }; 128 - 129 - struct tegra_mipi_device { 130 - struct platform_device *pdev; 131 - struct tegra_mipi *mipi; 132 - struct device *device; 133 - unsigned long pads; 134 - }; 135 - 136 - static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi, 137 - unsigned long offset) 23 + /** 24 + * tegra_mipi_enable - Enable the Tegra MIPI calibration device. 25 + * @device: Handle to the Tegra MIPI calibration device. 26 + * 27 + * This calls the enable sequence for the Tegra MIPI calibration device. 28 + * 29 + * Returns 0 on success or a negative error code on failure. 30 + */ 31 + int tegra_mipi_enable(struct tegra_mipi_device *device) 138 32 { 139 - return readl(mipi->regs + (offset << 2)); 140 - } 141 - 142 - static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value, 143 - unsigned long offset) 144 - { 145 - writel(value, mipi->regs + (offset << 2)); 146 - } 147 - 148 - static int tegra_mipi_power_up(struct tegra_mipi *mipi) 149 - { 150 - u32 value; 151 - int err; 152 - 153 - err = clk_enable(mipi->clk); 154 - if (err < 0) 155 - return err; 156 - 157 - value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0); 158 - value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; 159 - 160 - if (mipi->soc->needs_vclamp_ref) 161 - value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; 162 - 163 - tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0); 164 - 165 - value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2); 166 - value &= ~MIPI_CAL_BIAS_PAD_PDVREG; 167 - tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 168 - 169 - clk_disable(mipi->clk); 33 + if (device->ops->enable) 34 + return device->ops->enable(device); 170 35 171 36 return 0; 172 37 } 38 + EXPORT_SYMBOL(tegra_mipi_enable); 173 39 174 - static int tegra_mipi_power_down(struct tegra_mipi *mipi) 40 + /** 41 + * tegra_mipi_disable - Disable the Tegra MIPI calibration device. 42 + * @device: Handle to the Tegra MIPI calibration device. 43 + * 44 + * This calls the disable sequence for the Tegra MIPI calibration device. 45 + * 46 + * Returns 0 on success or a negative error code on failure. 47 + */ 48 + int tegra_mipi_disable(struct tegra_mipi_device *device) 175 49 { 176 - u32 value; 177 - int err; 178 - 179 - err = clk_enable(mipi->clk); 180 - if (err < 0) 181 - return err; 182 - 183 - /* 184 - * The MIPI_CAL_BIAS_PAD_PDVREG controls a voltage regulator that 185 - * supplies the DSI pads. This must be kept enabled until none of the 186 - * DSI lanes are used anymore. 187 - */ 188 - value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2); 189 - value |= MIPI_CAL_BIAS_PAD_PDVREG; 190 - tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 191 - 192 - /* 193 - * MIPI_CAL_BIAS_PAD_PDVCLAMP and MIPI_CAL_BIAS_PAD_E_VCLAMP_REF 194 - * control a regulator that supplies current to the pre-driver logic. 195 - * Powering down this regulator causes DSI to fail, so it must remain 196 - * powered on until none of the DSI lanes are used anymore. 197 - */ 198 - value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0); 199 - 200 - if (mipi->soc->needs_vclamp_ref) 201 - value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; 202 - 203 - value |= MIPI_CAL_BIAS_PAD_PDVCLAMP; 204 - tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0); 50 + if (device->ops->disable) 51 + return device->ops->disable(device); 205 52 206 53 return 0; 207 54 } 55 + EXPORT_SYMBOL(tegra_mipi_disable); 208 56 57 + /** 58 + * tegra_mipi_start_calibration - Start the Tegra MIPI calibration sequence. 59 + * @device: Handle to the Tegra MIPI calibration device. 60 + * 61 + * This initiates the calibration of CSI/DSI interfaces via the Tegra MIPI 62 + * calibration device. 63 + * 64 + * Returns 0 on success or a negative error code on failure. 65 + */ 66 + int tegra_mipi_start_calibration(struct tegra_mipi_device *device) 67 + { 68 + if (device->ops->start_calibration) 69 + return device->ops->start_calibration(device); 70 + 71 + return 0; 72 + } 73 + EXPORT_SYMBOL(tegra_mipi_start_calibration); 74 + 75 + /** 76 + * tegra_mipi_finish_calibration - Finish the Tegra MIPI calibration sequence. 77 + * @device: Handle to the Tegra MIPI calibration device. 78 + * 79 + * This completes the calibration of CSI/DSI interfaces via the Tegra MIPI 80 + * calibration device. 81 + * 82 + * Returns 0 on success or a negative error code on failure. 83 + */ 84 + int tegra_mipi_finish_calibration(struct tegra_mipi_device *device) 85 + { 86 + if (device->ops->finish_calibration) 87 + return device->ops->finish_calibration(device); 88 + 89 + return 0; 90 + } 91 + EXPORT_SYMBOL(tegra_mipi_finish_calibration); 92 + 93 + /** 94 + * tegra_mipi_request - Request a Tegra MIPI calibration device. 95 + * @device: Handle of the device requesting the MIPI calibration function. 96 + * @np: Device node pointer of the device requesting the MIPI calibration 97 + * function. 98 + * 99 + * This function requests a reference to a Tegra MIPI calibration device. 100 + * 101 + * Returns a pointer to the Tegra MIPI calibration device on success, 102 + * or an ERR_PTR-encoded error code on failure. 103 + */ 209 104 struct tegra_mipi_device *tegra_mipi_request(struct device *device, 210 105 struct device_node *np) 211 106 { 212 - struct tegra_mipi_device *dev; 107 + struct tegra_mipi_device *mipidev; 213 108 struct of_phandle_args args; 214 109 int err; 215 110 ··· 114 219 if (err < 0) 115 220 return ERR_PTR(err); 116 221 117 - dev = kzalloc_obj(*dev); 118 - if (!dev) { 222 + if (provider.np != args.np) 223 + return ERR_PTR(-ENODEV); 224 + 225 + mipidev = kzalloc_obj(*mipidev); 226 + if (!mipidev) { 119 227 err = -ENOMEM; 120 228 goto out; 121 229 } 122 230 123 - dev->pdev = of_find_device_by_node(args.np); 124 - if (!dev->pdev) { 231 + mipidev->pdev = of_find_device_by_node(args.np); 232 + if (!mipidev->pdev) { 125 233 err = -ENODEV; 126 234 goto free; 127 235 } 128 236 129 - dev->mipi = platform_get_drvdata(dev->pdev); 130 - if (!dev->mipi) { 131 - err = -EPROBE_DEFER; 132 - goto put; 133 - } 134 - 135 237 of_node_put(args.np); 136 238 137 - dev->pads = args.args[0]; 138 - dev->device = device; 239 + mipidev->ops = provider.ops; 240 + mipidev->pads = args.args[0]; 139 241 140 - return dev; 242 + return mipidev; 141 243 142 - put: 143 - platform_device_put(dev->pdev); 144 244 free: 145 - kfree(dev); 245 + kfree(mipidev); 146 246 out: 147 247 of_node_put(args.np); 148 248 return ERR_PTR(err); 149 249 } 150 250 EXPORT_SYMBOL(tegra_mipi_request); 151 251 152 - void tegra_mipi_free(struct tegra_mipi_device *device) 252 + /** 253 + * tegra_mipi_free - Free a Tegra MIPI calibration device. 254 + * @mipidev: Handle to the Tegra MIPI calibration device. 255 + * 256 + * This function releases a reference to a Tegra MIPI calibration device 257 + * previously requested by tegra_mipi_request(). 258 + */ 259 + void tegra_mipi_free(struct tegra_mipi_device *mipidev) 153 260 { 154 - platform_device_put(device->pdev); 155 - kfree(device); 261 + platform_device_put(mipidev->pdev); 262 + kfree(mipidev); 156 263 } 157 264 EXPORT_SYMBOL(tegra_mipi_free); 158 265 159 - int tegra_mipi_enable(struct tegra_mipi_device *dev) 266 + static void tegra_mipi_remove_provider(void *data) 160 267 { 161 - int err = 0; 162 - 163 - mutex_lock(&dev->mipi->lock); 164 - 165 - if (dev->mipi->usage_count++ == 0) 166 - err = tegra_mipi_power_up(dev->mipi); 167 - 168 - mutex_unlock(&dev->mipi->lock); 169 - 170 - return err; 171 - 172 - } 173 - EXPORT_SYMBOL(tegra_mipi_enable); 174 - 175 - int tegra_mipi_disable(struct tegra_mipi_device *dev) 176 - { 177 - int err = 0; 178 - 179 - mutex_lock(&dev->mipi->lock); 180 - 181 - if (--dev->mipi->usage_count == 0) 182 - err = tegra_mipi_power_down(dev->mipi); 183 - 184 - mutex_unlock(&dev->mipi->lock); 185 - 186 - return err; 187 - 188 - } 189 - EXPORT_SYMBOL(tegra_mipi_disable); 190 - 191 - int tegra_mipi_finish_calibration(struct tegra_mipi_device *device) 192 - { 193 - struct tegra_mipi *mipi = device->mipi; 194 - void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2); 195 - u32 value; 196 - int err; 197 - 198 - err = readl_relaxed_poll_timeout(status_reg, value, 199 - !(value & MIPI_CAL_STATUS_ACTIVE) && 200 - (value & MIPI_CAL_STATUS_DONE), 50, 201 - 250000); 202 - mutex_unlock(&device->mipi->lock); 203 - clk_disable(device->mipi->clk); 204 - 205 - return err; 206 - } 207 - EXPORT_SYMBOL(tegra_mipi_finish_calibration); 208 - 209 - int tegra_mipi_start_calibration(struct tegra_mipi_device *device) 210 - { 211 - const struct tegra_mipi_soc *soc = device->mipi->soc; 212 - unsigned int i; 213 - u32 value; 214 - int err; 215 - 216 - err = clk_enable(device->mipi->clk); 217 - if (err < 0) 218 - return err; 219 - 220 - mutex_lock(&device->mipi->lock); 221 - 222 - value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) | 223 - MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref); 224 - tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1); 225 - 226 - value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); 227 - value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); 228 - value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); 229 - value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level); 230 - value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level); 231 - tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 232 - 233 - for (i = 0; i < soc->num_pads; i++) { 234 - u32 clk = 0, data = 0; 235 - 236 - if (device->pads & BIT(i)) { 237 - data = MIPI_CAL_CONFIG_SELECT | 238 - MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) | 239 - MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) | 240 - MIPI_CAL_CONFIG_TERMOS(soc->termos); 241 - clk = MIPI_CAL_CONFIG_SELECT | 242 - MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) | 243 - MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos); 244 - } 245 - 246 - tegra_mipi_writel(device->mipi, data, soc->pads[i].data); 247 - 248 - if (soc->has_clk_lane && soc->pads[i].clk != 0) 249 - tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk); 250 - } 251 - 252 - value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL); 253 - value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf); 254 - value &= ~MIPI_CAL_CTRL_PRESCALE(0x3); 255 - value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa); 256 - value |= MIPI_CAL_CTRL_PRESCALE(0x2); 257 - 258 - if (!soc->clock_enable_override) 259 - value &= ~MIPI_CAL_CTRL_CLKEN_OVR; 260 - else 261 - value |= MIPI_CAL_CTRL_CLKEN_OVR; 262 - 263 - tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL); 264 - 265 - /* clear any pending status bits */ 266 - value = tegra_mipi_readl(device->mipi, MIPI_CAL_STATUS); 267 - tegra_mipi_writel(device->mipi, value, MIPI_CAL_STATUS); 268 - 269 - value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL); 270 - value |= MIPI_CAL_CTRL_START; 271 - tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL); 272 - 273 - /* 274 - * Wait for min 72uS to let calibration logic finish calibration 275 - * sequence codes before waiting for pads idle state to apply the 276 - * results. 277 - */ 278 - usleep_range(75, 80); 279 - 280 - return 0; 281 - } 282 - EXPORT_SYMBOL(tegra_mipi_start_calibration); 283 - 284 - static const struct tegra_mipi_pad tegra114_mipi_pads[] = { 285 - { .data = MIPI_CAL_CONFIG_CSIA }, 286 - { .data = MIPI_CAL_CONFIG_CSIB }, 287 - { .data = MIPI_CAL_CONFIG_CSIC }, 288 - { .data = MIPI_CAL_CONFIG_CSID }, 289 - { .data = MIPI_CAL_CONFIG_CSIE }, 290 - { .data = MIPI_CAL_CONFIG_DSIA }, 291 - { .data = MIPI_CAL_CONFIG_DSIB }, 292 - { .data = MIPI_CAL_CONFIG_DSIC }, 293 - { .data = MIPI_CAL_CONFIG_DSID }, 294 - }; 295 - 296 - static const struct tegra_mipi_soc tegra114_mipi_soc = { 297 - .has_clk_lane = false, 298 - .pads = tegra114_mipi_pads, 299 - .num_pads = ARRAY_SIZE(tegra114_mipi_pads), 300 - .clock_enable_override = true, 301 - .needs_vclamp_ref = true, 302 - .pad_drive_down_ref = 0x2, 303 - .pad_drive_up_ref = 0x0, 304 - .pad_vclamp_level = 0x0, 305 - .pad_vauxp_level = 0x0, 306 - .hspdos = 0x0, 307 - .hspuos = 0x4, 308 - .termos = 0x5, 309 - .hsclkpdos = 0x0, 310 - .hsclkpuos = 0x4, 311 - }; 312 - 313 - static const struct tegra_mipi_pad tegra124_mipi_pads[] = { 314 - { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, 315 - { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, 316 - { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, 317 - { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, 318 - { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK }, 319 - { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK }, 320 - { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK }, 321 - }; 322 - 323 - static const struct tegra_mipi_soc tegra124_mipi_soc = { 324 - .has_clk_lane = true, 325 - .pads = tegra124_mipi_pads, 326 - .num_pads = ARRAY_SIZE(tegra124_mipi_pads), 327 - .clock_enable_override = true, 328 - .needs_vclamp_ref = true, 329 - .pad_drive_down_ref = 0x2, 330 - .pad_drive_up_ref = 0x0, 331 - .pad_vclamp_level = 0x0, 332 - .pad_vauxp_level = 0x0, 333 - .hspdos = 0x0, 334 - .hspuos = 0x0, 335 - .termos = 0x0, 336 - .hsclkpdos = 0x1, 337 - .hsclkpuos = 0x2, 338 - }; 339 - 340 - static const struct tegra_mipi_soc tegra132_mipi_soc = { 341 - .has_clk_lane = true, 342 - .pads = tegra124_mipi_pads, 343 - .num_pads = ARRAY_SIZE(tegra124_mipi_pads), 344 - .clock_enable_override = false, 345 - .needs_vclamp_ref = false, 346 - .pad_drive_down_ref = 0x0, 347 - .pad_drive_up_ref = 0x3, 348 - .pad_vclamp_level = 0x0, 349 - .pad_vauxp_level = 0x0, 350 - .hspdos = 0x0, 351 - .hspuos = 0x0, 352 - .termos = 0x0, 353 - .hsclkpdos = 0x3, 354 - .hsclkpuos = 0x2, 355 - }; 356 - 357 - static const struct tegra_mipi_pad tegra210_mipi_pads[] = { 358 - { .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 }, 359 - { .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 }, 360 - { .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 }, 361 - { .data = MIPI_CAL_CONFIG_CSID, .clk = 0 }, 362 - { .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 }, 363 - { .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 }, 364 - { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK }, 365 - { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK }, 366 - { .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK }, 367 - { .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK }, 368 - }; 369 - 370 - static const struct tegra_mipi_soc tegra210_mipi_soc = { 371 - .has_clk_lane = true, 372 - .pads = tegra210_mipi_pads, 373 - .num_pads = ARRAY_SIZE(tegra210_mipi_pads), 374 - .clock_enable_override = true, 375 - .needs_vclamp_ref = false, 376 - .pad_drive_down_ref = 0x0, 377 - .pad_drive_up_ref = 0x3, 378 - .pad_vclamp_level = 0x1, 379 - .pad_vauxp_level = 0x1, 380 - .hspdos = 0x0, 381 - .hspuos = 0x2, 382 - .termos = 0x0, 383 - .hsclkpdos = 0x0, 384 - .hsclkpuos = 0x2, 385 - }; 386 - 387 - static const struct of_device_id tegra_mipi_of_match[] = { 388 - { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc }, 389 - { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc }, 390 - { .compatible = "nvidia,tegra132-mipi", .data = &tegra132_mipi_soc }, 391 - { .compatible = "nvidia,tegra210-mipi", .data = &tegra210_mipi_soc }, 392 - { }, 393 - }; 394 - 395 - static int tegra_mipi_probe(struct platform_device *pdev) 396 - { 397 - const struct of_device_id *match; 398 - struct tegra_mipi *mipi; 399 - 400 - match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node); 401 - if (!match) 402 - return -ENODEV; 403 - 404 - mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); 405 - if (!mipi) 406 - return -ENOMEM; 407 - 408 - mipi->soc = match->data; 409 - mipi->dev = &pdev->dev; 410 - 411 - mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 412 - if (IS_ERR(mipi->regs)) 413 - return PTR_ERR(mipi->regs); 414 - 415 - mutex_init(&mipi->lock); 416 - 417 - mipi->clk = devm_clk_get_prepared(&pdev->dev, NULL); 418 - if (IS_ERR(mipi->clk)) { 419 - dev_err(&pdev->dev, "failed to get clock\n"); 420 - return PTR_ERR(mipi->clk); 421 - } 422 - 423 - platform_set_drvdata(pdev, mipi); 424 - 425 - return 0; 268 + provider.np = NULL; 269 + provider.ops = NULL; 426 270 } 427 271 428 - struct platform_driver tegra_mipi_driver = { 429 - .driver = { 430 - .name = "tegra-mipi", 431 - .of_match_table = tegra_mipi_of_match, 432 - }, 433 - .probe = tegra_mipi_probe, 434 - }; 272 + /** 273 + * devm_tegra_mipi_add_provider - Managed registration of a Tegra MIPI 274 + * calibration function provider. 275 + * @device: Handle to the device providing the MIPI calibration function. 276 + * @np: Device node pointer of the device providing the MIPI calibration 277 + * function. 278 + * @ops: Operations supported by the MIPI calibration device. 279 + * 280 + * This registers a device that provides MIPI calibration functions. 281 + * For Tegra20 and Tegra30, this is the CSI block, while Tegra114 and 282 + * newer SoC generations have a dedicated hardware block for these 283 + * functions. 284 + * 285 + * Returns 0 on success or a negative error code on failure. 286 + */ 287 + int devm_tegra_mipi_add_provider(struct device *device, struct device_node *np, 288 + const struct tegra_mipi_ops *ops) 289 + { 290 + if (provider.np) 291 + return -EBUSY; 292 + 293 + provider.np = np; 294 + provider.ops = ops; 295 + 296 + return devm_add_action_or_reset(device, tegra_mipi_remove_provider, NULL); 297 + } 298 + EXPORT_SYMBOL(devm_tegra_mipi_add_provider);
+483
drivers/gpu/host1x/tegra114-mipi.c
··· 1 + /* 2 + * Copyright (C) 2013 NVIDIA Corporation 3 + * 4 + * Permission to use, copy, modify, distribute, and sell this software and its 5 + * documentation for any purpose is hereby granted without fee, provided that 6 + * the above copyright notice appear in all copies and that both that copyright 7 + * notice and this permission notice appear in supporting documentation, and 8 + * that the name of the copyright holders not be used in advertising or 9 + * publicity pertaining to distribution of the software without specific, 10 + * written prior permission. The copyright holders make no representations 11 + * about the suitability of this software for any purpose. It is provided "as 12 + * is" without express or implied warranty. 13 + * 14 + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 + * OF THIS SOFTWARE. 21 + */ 22 + 23 + #include <linux/clk.h> 24 + #include <linux/host1x.h> 25 + #include <linux/io.h> 26 + #include <linux/iopoll.h> 27 + #include <linux/of_platform.h> 28 + #include <linux/platform_device.h> 29 + #include <linux/slab.h> 30 + #include <linux/tegra-mipi-cal.h> 31 + 32 + #include "dev.h" 33 + 34 + #define MIPI_CAL_CTRL 0x00 35 + #define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26) 36 + #define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24) 37 + #define MIPI_CAL_CTRL_CLKEN_OVR BIT(4) 38 + #define MIPI_CAL_CTRL_START BIT(0) 39 + 40 + #define MIPI_CAL_AUTOCAL_CTRL 0x01 41 + 42 + #define MIPI_CAL_STATUS 0x02 43 + #define MIPI_CAL_STATUS_DONE BIT(16) 44 + #define MIPI_CAL_STATUS_ACTIVE BIT(0) 45 + 46 + #define MIPI_CAL_CONFIG_CSIA 0x05 47 + #define MIPI_CAL_CONFIG_CSIB 0x06 48 + #define MIPI_CAL_CONFIG_CSIC 0x07 49 + #define MIPI_CAL_CONFIG_CSID 0x08 50 + #define MIPI_CAL_CONFIG_CSIE 0x09 51 + #define MIPI_CAL_CONFIG_CSIF 0x0a 52 + #define MIPI_CAL_CONFIG_DSIA 0x0e 53 + #define MIPI_CAL_CONFIG_DSIB 0x0f 54 + #define MIPI_CAL_CONFIG_DSIC 0x10 55 + #define MIPI_CAL_CONFIG_DSID 0x11 56 + 57 + #define MIPI_CAL_CONFIG_DSIA_CLK 0x19 58 + #define MIPI_CAL_CONFIG_DSIB_CLK 0x1a 59 + #define MIPI_CAL_CONFIG_CSIAB_CLK 0x1b 60 + #define MIPI_CAL_CONFIG_DSIC_CLK 0x1c 61 + #define MIPI_CAL_CONFIG_CSICD_CLK 0x1c 62 + #define MIPI_CAL_CONFIG_DSID_CLK 0x1d 63 + #define MIPI_CAL_CONFIG_CSIE_CLK 0x1d 64 + 65 + /* for data and clock lanes */ 66 + #define MIPI_CAL_CONFIG_SELECT BIT(21) 67 + 68 + /* for data lanes */ 69 + #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) 70 + #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) 71 + #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) 72 + 73 + /* for clock lanes */ 74 + #define MIPI_CAL_CONFIG_HSCLKPDOSD(x) (((x) & 0x1f) << 8) 75 + #define MIPI_CAL_CONFIG_HSCLKPUOSD(x) (((x) & 0x1f) << 0) 76 + 77 + #define MIPI_CAL_BIAS_PAD_CFG0 0x16 78 + #define MIPI_CAL_BIAS_PAD_PDVCLAMP BIT(1) 79 + #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF BIT(0) 80 + 81 + #define MIPI_CAL_BIAS_PAD_CFG1 0x17 82 + #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) 83 + #define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8) 84 + 85 + #define MIPI_CAL_BIAS_PAD_CFG2 0x18 86 + #define MIPI_CAL_BIAS_PAD_VCLAMP(x) (((x) & 0x7) << 16) 87 + #define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4) 88 + #define MIPI_CAL_BIAS_PAD_PDVREG BIT(1) 89 + 90 + struct tegra_mipi_pad { 91 + unsigned long data; 92 + unsigned long clk; 93 + }; 94 + 95 + struct tegra_mipi_soc { 96 + bool has_clk_lane; 97 + const struct tegra_mipi_pad *pads; 98 + unsigned int num_pads; 99 + 100 + bool clock_enable_override; 101 + bool needs_vclamp_ref; 102 + 103 + /* bias pad configuration settings */ 104 + u8 pad_drive_down_ref; 105 + u8 pad_drive_up_ref; 106 + 107 + u8 pad_vclamp_level; 108 + u8 pad_vauxp_level; 109 + 110 + /* calibration settings for data lanes */ 111 + u8 hspdos; 112 + u8 hspuos; 113 + u8 termos; 114 + 115 + /* calibration settings for clock lanes */ 116 + u8 hsclkpdos; 117 + u8 hsclkpuos; 118 + }; 119 + 120 + struct tegra_mipi { 121 + const struct tegra_mipi_soc *soc; 122 + struct device *dev; 123 + void __iomem *regs; 124 + struct mutex lock; /* for register access */ 125 + struct clk *clk; 126 + 127 + unsigned long usage_count; 128 + }; 129 + 130 + static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi, 131 + unsigned long offset) 132 + { 133 + return readl(mipi->regs + (offset << 2)); 134 + } 135 + 136 + static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value, 137 + unsigned long offset) 138 + { 139 + writel(value, mipi->regs + (offset << 2)); 140 + } 141 + 142 + static int tegra114_mipi_power_up(struct tegra_mipi *mipi) 143 + { 144 + u32 value; 145 + int err; 146 + 147 + err = clk_enable(mipi->clk); 148 + if (err < 0) 149 + return err; 150 + 151 + value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0); 152 + value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; 153 + 154 + if (mipi->soc->needs_vclamp_ref) 155 + value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; 156 + 157 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0); 158 + 159 + value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2); 160 + value &= ~MIPI_CAL_BIAS_PAD_PDVREG; 161 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 162 + 163 + clk_disable(mipi->clk); 164 + 165 + return 0; 166 + } 167 + 168 + static int tegra114_mipi_power_down(struct tegra_mipi *mipi) 169 + { 170 + u32 value; 171 + int err; 172 + 173 + err = clk_enable(mipi->clk); 174 + if (err < 0) 175 + return err; 176 + 177 + /* 178 + * The MIPI_CAL_BIAS_PAD_PDVREG controls a voltage regulator that 179 + * supplies the DSI pads. This must be kept enabled until none of the 180 + * DSI lanes are used anymore. 181 + */ 182 + value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2); 183 + value |= MIPI_CAL_BIAS_PAD_PDVREG; 184 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 185 + 186 + /* 187 + * MIPI_CAL_BIAS_PAD_PDVCLAMP and MIPI_CAL_BIAS_PAD_E_VCLAMP_REF 188 + * control a regulator that supplies current to the pre-driver logic. 189 + * Powering down this regulator causes DSI to fail, so it must remain 190 + * powered on until none of the DSI lanes are used anymore. 191 + */ 192 + value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0); 193 + 194 + if (mipi->soc->needs_vclamp_ref) 195 + value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; 196 + 197 + value |= MIPI_CAL_BIAS_PAD_PDVCLAMP; 198 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0); 199 + 200 + return 0; 201 + } 202 + 203 + static int tegra114_mipi_enable(struct tegra_mipi_device *mipidev) 204 + { 205 + struct tegra_mipi *mipi = platform_get_drvdata(mipidev->pdev); 206 + int err = 0; 207 + 208 + mutex_lock(&mipi->lock); 209 + 210 + if (mipi->usage_count++ == 0) 211 + err = tegra114_mipi_power_up(mipi); 212 + 213 + mutex_unlock(&mipi->lock); 214 + 215 + return err; 216 + } 217 + 218 + static int tegra114_mipi_disable(struct tegra_mipi_device *mipidev) 219 + { 220 + struct tegra_mipi *mipi = platform_get_drvdata(mipidev->pdev); 221 + int err = 0; 222 + 223 + mutex_lock(&mipi->lock); 224 + 225 + if (--mipi->usage_count == 0) 226 + err = tegra114_mipi_power_down(mipi); 227 + 228 + mutex_unlock(&mipi->lock); 229 + 230 + return err; 231 + } 232 + 233 + static int tegra114_mipi_finish_calibration(struct tegra_mipi_device *mipidev) 234 + { 235 + struct tegra_mipi *mipi = platform_get_drvdata(mipidev->pdev); 236 + void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2); 237 + u32 value; 238 + int err; 239 + 240 + err = readl_relaxed_poll_timeout(status_reg, value, 241 + !(value & MIPI_CAL_STATUS_ACTIVE) && 242 + (value & MIPI_CAL_STATUS_DONE), 50, 243 + 250000); 244 + mutex_unlock(&mipi->lock); 245 + clk_disable(mipi->clk); 246 + 247 + return err; 248 + } 249 + 250 + static int tegra114_mipi_start_calibration(struct tegra_mipi_device *mipidev) 251 + { 252 + struct tegra_mipi *mipi = platform_get_drvdata(mipidev->pdev); 253 + const struct tegra_mipi_soc *soc = mipi->soc; 254 + unsigned int i; 255 + u32 value; 256 + int err; 257 + 258 + err = clk_enable(mipi->clk); 259 + if (err < 0) 260 + return err; 261 + 262 + mutex_lock(&mipi->lock); 263 + 264 + value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) | 265 + MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref); 266 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG1); 267 + 268 + value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2); 269 + value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); 270 + value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); 271 + value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level); 272 + value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level); 273 + tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2); 274 + 275 + for (i = 0; i < soc->num_pads; i++) { 276 + u32 clk = 0, data = 0; 277 + 278 + if (mipidev->pads & BIT(i)) { 279 + data = MIPI_CAL_CONFIG_SELECT | 280 + MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) | 281 + MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) | 282 + MIPI_CAL_CONFIG_TERMOS(soc->termos); 283 + clk = MIPI_CAL_CONFIG_SELECT | 284 + MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) | 285 + MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos); 286 + } 287 + 288 + tegra_mipi_writel(mipi, data, soc->pads[i].data); 289 + 290 + if (soc->has_clk_lane && soc->pads[i].clk != 0) 291 + tegra_mipi_writel(mipi, clk, soc->pads[i].clk); 292 + } 293 + 294 + value = tegra_mipi_readl(mipi, MIPI_CAL_CTRL); 295 + value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf); 296 + value &= ~MIPI_CAL_CTRL_PRESCALE(0x3); 297 + value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa); 298 + value |= MIPI_CAL_CTRL_PRESCALE(0x2); 299 + 300 + if (!soc->clock_enable_override) 301 + value &= ~MIPI_CAL_CTRL_CLKEN_OVR; 302 + else 303 + value |= MIPI_CAL_CTRL_CLKEN_OVR; 304 + 305 + tegra_mipi_writel(mipi, value, MIPI_CAL_CTRL); 306 + 307 + /* clear any pending status bits */ 308 + value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); 309 + tegra_mipi_writel(mipi, value, MIPI_CAL_STATUS); 310 + 311 + value = tegra_mipi_readl(mipi, MIPI_CAL_CTRL); 312 + value |= MIPI_CAL_CTRL_START; 313 + tegra_mipi_writel(mipi, value, MIPI_CAL_CTRL); 314 + 315 + /* 316 + * Wait for min 72uS to let calibration logic finish calibration 317 + * sequence codes before waiting for pads idle state to apply the 318 + * results. 319 + */ 320 + usleep_range(75, 80); 321 + 322 + return 0; 323 + } 324 + 325 + static const struct tegra_mipi_ops tegra114_mipi_ops = { 326 + .enable = tegra114_mipi_enable, 327 + .disable = tegra114_mipi_disable, 328 + .start_calibration = tegra114_mipi_start_calibration, 329 + .finish_calibration = tegra114_mipi_finish_calibration, 330 + }; 331 + 332 + static const struct tegra_mipi_pad tegra114_mipi_pads[] = { 333 + { .data = MIPI_CAL_CONFIG_CSIA }, 334 + { .data = MIPI_CAL_CONFIG_CSIB }, 335 + { .data = MIPI_CAL_CONFIG_CSIC }, 336 + { .data = MIPI_CAL_CONFIG_CSID }, 337 + { .data = MIPI_CAL_CONFIG_CSIE }, 338 + { .data = MIPI_CAL_CONFIG_DSIA }, 339 + { .data = MIPI_CAL_CONFIG_DSIB }, 340 + { .data = MIPI_CAL_CONFIG_DSIC }, 341 + { .data = MIPI_CAL_CONFIG_DSID }, 342 + }; 343 + 344 + static const struct tegra_mipi_soc tegra114_mipi_soc = { 345 + .has_clk_lane = false, 346 + .pads = tegra114_mipi_pads, 347 + .num_pads = ARRAY_SIZE(tegra114_mipi_pads), 348 + .clock_enable_override = true, 349 + .needs_vclamp_ref = true, 350 + .pad_drive_down_ref = 0x2, 351 + .pad_drive_up_ref = 0x0, 352 + .pad_vclamp_level = 0x0, 353 + .pad_vauxp_level = 0x0, 354 + .hspdos = 0x0, 355 + .hspuos = 0x4, 356 + .termos = 0x5, 357 + .hsclkpdos = 0x0, 358 + .hsclkpuos = 0x4, 359 + }; 360 + 361 + static const struct tegra_mipi_pad tegra124_mipi_pads[] = { 362 + { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, 363 + { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, 364 + { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, 365 + { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, 366 + { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK }, 367 + { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK }, 368 + { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK }, 369 + }; 370 + 371 + static const struct tegra_mipi_soc tegra124_mipi_soc = { 372 + .has_clk_lane = true, 373 + .pads = tegra124_mipi_pads, 374 + .num_pads = ARRAY_SIZE(tegra124_mipi_pads), 375 + .clock_enable_override = true, 376 + .needs_vclamp_ref = true, 377 + .pad_drive_down_ref = 0x2, 378 + .pad_drive_up_ref = 0x0, 379 + .pad_vclamp_level = 0x0, 380 + .pad_vauxp_level = 0x0, 381 + .hspdos = 0x0, 382 + .hspuos = 0x0, 383 + .termos = 0x0, 384 + .hsclkpdos = 0x1, 385 + .hsclkpuos = 0x2, 386 + }; 387 + 388 + static const struct tegra_mipi_soc tegra132_mipi_soc = { 389 + .has_clk_lane = true, 390 + .pads = tegra124_mipi_pads, 391 + .num_pads = ARRAY_SIZE(tegra124_mipi_pads), 392 + .clock_enable_override = false, 393 + .needs_vclamp_ref = false, 394 + .pad_drive_down_ref = 0x0, 395 + .pad_drive_up_ref = 0x3, 396 + .pad_vclamp_level = 0x0, 397 + .pad_vauxp_level = 0x0, 398 + .hspdos = 0x0, 399 + .hspuos = 0x0, 400 + .termos = 0x0, 401 + .hsclkpdos = 0x3, 402 + .hsclkpuos = 0x2, 403 + }; 404 + 405 + static const struct tegra_mipi_pad tegra210_mipi_pads[] = { 406 + { .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 }, 407 + { .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 }, 408 + { .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 }, 409 + { .data = MIPI_CAL_CONFIG_CSID, .clk = 0 }, 410 + { .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 }, 411 + { .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 }, 412 + { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK }, 413 + { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK }, 414 + { .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK }, 415 + { .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK }, 416 + }; 417 + 418 + static const struct tegra_mipi_soc tegra210_mipi_soc = { 419 + .has_clk_lane = true, 420 + .pads = tegra210_mipi_pads, 421 + .num_pads = ARRAY_SIZE(tegra210_mipi_pads), 422 + .clock_enable_override = true, 423 + .needs_vclamp_ref = false, 424 + .pad_drive_down_ref = 0x0, 425 + .pad_drive_up_ref = 0x3, 426 + .pad_vclamp_level = 0x1, 427 + .pad_vauxp_level = 0x1, 428 + .hspdos = 0x0, 429 + .hspuos = 0x2, 430 + .termos = 0x0, 431 + .hsclkpdos = 0x0, 432 + .hsclkpuos = 0x2, 433 + }; 434 + 435 + static const struct of_device_id tegra_mipi_of_match[] = { 436 + { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc }, 437 + { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc }, 438 + { .compatible = "nvidia,tegra132-mipi", .data = &tegra132_mipi_soc }, 439 + { .compatible = "nvidia,tegra210-mipi", .data = &tegra210_mipi_soc }, 440 + { }, 441 + }; 442 + 443 + static int tegra_mipi_probe(struct platform_device *pdev) 444 + { 445 + const struct of_device_id *match; 446 + struct tegra_mipi *mipi; 447 + 448 + match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node); 449 + if (!match) 450 + return -ENODEV; 451 + 452 + mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); 453 + if (!mipi) 454 + return -ENOMEM; 455 + 456 + mipi->soc = match->data; 457 + mipi->dev = &pdev->dev; 458 + 459 + mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 460 + if (IS_ERR(mipi->regs)) 461 + return PTR_ERR(mipi->regs); 462 + 463 + mutex_init(&mipi->lock); 464 + 465 + mipi->clk = devm_clk_get_prepared(&pdev->dev, NULL); 466 + if (IS_ERR(mipi->clk)) { 467 + dev_err(&pdev->dev, "failed to get clock\n"); 468 + return PTR_ERR(mipi->clk); 469 + } 470 + 471 + platform_set_drvdata(pdev, mipi); 472 + 473 + return devm_tegra_mipi_add_provider(&pdev->dev, pdev->dev.of_node, 474 + &tegra114_mipi_ops); 475 + } 476 + 477 + struct platform_driver tegra_mipi_driver = { 478 + .driver = { 479 + .name = "tegra-mipi", 480 + .of_match_table = tegra_mipi_of_match, 481 + }, 482 + .probe = tegra_mipi_probe, 483 + };
+1
drivers/staging/media/tegra-video/csi.c
··· 12 12 #include <linux/of_graph.h> 13 13 #include <linux/platform_device.h> 14 14 #include <linux/pm_runtime.h> 15 + #include <linux/tegra-mipi-cal.h> 15 16 16 17 #include <media/v4l2-fwnode.h> 17 18
-10
include/linux/host1x.h
··· 453 453 int host1x_client_suspend(struct host1x_client *client); 454 454 int host1x_client_resume(struct host1x_client *client); 455 455 456 - struct tegra_mipi_device; 457 - 458 - struct tegra_mipi_device *tegra_mipi_request(struct device *device, 459 - struct device_node *np); 460 - void tegra_mipi_free(struct tegra_mipi_device *device); 461 - int tegra_mipi_enable(struct tegra_mipi_device *device); 462 - int tegra_mipi_disable(struct tegra_mipi_device *device); 463 - int tegra_mipi_start_calibration(struct tegra_mipi_device *device); 464 - int tegra_mipi_finish_calibration(struct tegra_mipi_device *device); 465 - 466 456 /* host1x memory contexts */ 467 457 468 458 struct host1x_memory_context {
+57
include/linux/tegra-mipi-cal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __TEGRA_MIPI_CAL_H_ 4 + #define __TEGRA_MIPI_CAL_H_ 5 + 6 + struct tegra_mipi_device { 7 + const struct tegra_mipi_ops *ops; 8 + struct platform_device *pdev; 9 + unsigned long pads; 10 + }; 11 + 12 + /** 13 + * Operations for Tegra MIPI calibration device 14 + */ 15 + struct tegra_mipi_ops { 16 + /** 17 + * @enable: 18 + * 19 + * Enable MIPI calibration device 20 + */ 21 + int (*enable)(struct tegra_mipi_device *device); 22 + 23 + /** 24 + * @disable: 25 + * 26 + * Disable MIPI calibration device 27 + */ 28 + int (*disable)(struct tegra_mipi_device *device); 29 + 30 + /** 31 + * @start_calibration: 32 + * 33 + * Start MIPI calibration 34 + */ 35 + int (*start_calibration)(struct tegra_mipi_device *device); 36 + 37 + /** 38 + * @finish_calibration: 39 + * 40 + * Finish MIPI calibration 41 + */ 42 + int (*finish_calibration)(struct tegra_mipi_device *device); 43 + }; 44 + 45 + int devm_tegra_mipi_add_provider(struct device *device, struct device_node *np, 46 + const struct tegra_mipi_ops *ops); 47 + 48 + struct tegra_mipi_device *tegra_mipi_request(struct device *device, 49 + struct device_node *np); 50 + void tegra_mipi_free(struct tegra_mipi_device *device); 51 + 52 + int tegra_mipi_enable(struct tegra_mipi_device *device); 53 + int tegra_mipi_disable(struct tegra_mipi_device *device); 54 + int tegra_mipi_start_calibration(struct tegra_mipi_device *device); 55 + int tegra_mipi_finish_calibration(struct tegra_mipi_device *device); 56 + 57 + #endif /* __TEGRA_MIPI_CAL_H_ */