diff options
Diffstat (limited to 'drivers/gpu/host1x/mipi.c')
| -rw-r--r-- | drivers/gpu/host1x/mipi.c | 148 |
1 files changed, 107 insertions, 41 deletions
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c index 9882ea122024..fbc6ee6ca337 100644 --- a/drivers/gpu/host1x/mipi.c +++ b/drivers/gpu/host1x/mipi.c | |||
| @@ -49,35 +49,47 @@ | |||
| 49 | #define MIPI_CAL_CONFIG_DSIC 0x10 | 49 | #define MIPI_CAL_CONFIG_DSIC 0x10 |
| 50 | #define MIPI_CAL_CONFIG_DSID 0x11 | 50 | #define MIPI_CAL_CONFIG_DSID 0x11 |
| 51 | 51 | ||
| 52 | #define MIPI_CAL_CONFIG_DSIAB_CLK 0x19 | ||
| 53 | #define MIPI_CAL_CONFIG_DSICD_CLK 0x1a | ||
| 54 | #define MIPI_CAL_CONFIG_CSIAB_CLK 0x1b | ||
| 55 | #define MIPI_CAL_CONFIG_CSICD_CLK 0x1c | ||
| 56 | #define MIPI_CAL_CONFIG_CSIE_CLK 0x1d | ||
| 57 | |||
| 58 | /* for data and clock lanes */ | ||
| 52 | #define MIPI_CAL_CONFIG_SELECT (1 << 21) | 59 | #define MIPI_CAL_CONFIG_SELECT (1 << 21) |
| 60 | |||
| 61 | /* for data lanes */ | ||
| 53 | #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) | 62 | #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) |
| 54 | #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) | 63 | #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) |
| 55 | #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) | 64 | #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) |
| 56 | 65 | ||
| 66 | /* for clock lanes */ | ||
| 67 | #define MIPI_CAL_CONFIG_HSCLKPDOSD(x) (((x) & 0x1f) << 8) | ||
| 68 | #define MIPI_CAL_CONFIG_HSCLKPUOSD(x) (((x) & 0x1f) << 0) | ||
| 69 | |||
| 57 | #define MIPI_CAL_BIAS_PAD_CFG0 0x16 | 70 | #define MIPI_CAL_BIAS_PAD_CFG0 0x16 |
| 58 | #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) | 71 | #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) |
| 59 | #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) | 72 | #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) |
| 60 | 73 | ||
| 61 | #define MIPI_CAL_BIAS_PAD_CFG1 0x17 | 74 | #define MIPI_CAL_BIAS_PAD_CFG1 0x17 |
| 75 | #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) | ||
| 62 | 76 | ||
| 63 | #define MIPI_CAL_BIAS_PAD_CFG2 0x18 | 77 | #define MIPI_CAL_BIAS_PAD_CFG2 0x18 |
| 64 | #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) | 78 | #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) |
| 65 | 79 | ||
| 66 | static const struct module { | 80 | struct tegra_mipi_pad { |
| 67 | unsigned long reg; | 81 | unsigned long data; |
| 68 | } modules[] = { | 82 | unsigned long clk; |
| 69 | { .reg = MIPI_CAL_CONFIG_CSIA }, | 83 | }; |
| 70 | { .reg = MIPI_CAL_CONFIG_CSIB }, | 84 | |
| 71 | { .reg = MIPI_CAL_CONFIG_CSIC }, | 85 | struct tegra_mipi_soc { |
| 72 | { .reg = MIPI_CAL_CONFIG_CSID }, | 86 | bool has_clk_lane; |
| 73 | { .reg = MIPI_CAL_CONFIG_CSIE }, | 87 | const struct tegra_mipi_pad *pads; |
| 74 | { .reg = MIPI_CAL_CONFIG_DSIA }, | 88 | unsigned int num_pads; |
| 75 | { .reg = MIPI_CAL_CONFIG_DSIB }, | ||
| 76 | { .reg = MIPI_CAL_CONFIG_DSIC }, | ||
| 77 | { .reg = MIPI_CAL_CONFIG_DSID }, | ||
| 78 | }; | 89 | }; |
| 79 | 90 | ||
| 80 | struct tegra_mipi { | 91 | struct tegra_mipi { |
| 92 | const struct tegra_mipi_soc *soc; | ||
| 81 | void __iomem *regs; | 93 | void __iomem *regs; |
| 82 | struct mutex lock; | 94 | struct mutex lock; |
| 83 | struct clk *clk; | 95 | struct clk *clk; |
| @@ -90,16 +102,16 @@ struct tegra_mipi_device { | |||
| 90 | unsigned long pads; | 102 | unsigned long pads; |
| 91 | }; | 103 | }; |
| 92 | 104 | ||
| 93 | static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi, | 105 | static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi, |
| 94 | unsigned long reg) | 106 | unsigned long offset) |
| 95 | { | 107 | { |
| 96 | return readl(mipi->regs + (reg << 2)); | 108 | return readl(mipi->regs + (offset << 2)); |
| 97 | } | 109 | } |
| 98 | 110 | ||
| 99 | static inline void tegra_mipi_writel(struct tegra_mipi *mipi, | 111 | static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value, |
| 100 | unsigned long value, unsigned long reg) | 112 | unsigned long offset) |
| 101 | { | 113 | { |
| 102 | writel(value, mipi->regs + (reg << 2)); | 114 | writel(value, mipi->regs + (offset << 2)); |
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | struct tegra_mipi_device *tegra_mipi_request(struct device *device) | 117 | struct tegra_mipi_device *tegra_mipi_request(struct device *device) |
| @@ -117,36 +129,35 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device) | |||
| 117 | 129 | ||
| 118 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 130 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
| 119 | if (!dev) { | 131 | if (!dev) { |
| 120 | of_node_put(args.np); | ||
| 121 | err = -ENOMEM; | 132 | err = -ENOMEM; |
| 122 | goto out; | 133 | goto out; |
| 123 | } | 134 | } |
| 124 | 135 | ||
| 125 | dev->pdev = of_find_device_by_node(args.np); | 136 | dev->pdev = of_find_device_by_node(args.np); |
| 126 | if (!dev->pdev) { | 137 | if (!dev->pdev) { |
| 127 | of_node_put(args.np); | ||
| 128 | err = -ENODEV; | 138 | err = -ENODEV; |
| 129 | goto free; | 139 | goto free; |
| 130 | } | 140 | } |
| 131 | 141 | ||
| 132 | of_node_put(args.np); | ||
| 133 | |||
| 134 | dev->mipi = platform_get_drvdata(dev->pdev); | 142 | dev->mipi = platform_get_drvdata(dev->pdev); |
| 135 | if (!dev->mipi) { | 143 | if (!dev->mipi) { |
| 136 | err = -EPROBE_DEFER; | 144 | err = -EPROBE_DEFER; |
| 137 | goto pdev_put; | 145 | goto put; |
| 138 | } | 146 | } |
| 139 | 147 | ||
| 148 | of_node_put(args.np); | ||
| 149 | |||
| 140 | dev->pads = args.args[0]; | 150 | dev->pads = args.args[0]; |
| 141 | dev->device = device; | 151 | dev->device = device; |
| 142 | 152 | ||
| 143 | return dev; | 153 | return dev; |
| 144 | 154 | ||
| 145 | pdev_put: | 155 | put: |
| 146 | platform_device_put(dev->pdev); | 156 | platform_device_put(dev->pdev); |
| 147 | free: | 157 | free: |
| 148 | kfree(dev); | 158 | kfree(dev); |
| 149 | out: | 159 | out: |
| 160 | of_node_put(args.np); | ||
| 150 | return ERR_PTR(err); | 161 | return ERR_PTR(err); |
| 151 | } | 162 | } |
| 152 | EXPORT_SYMBOL(tegra_mipi_request); | 163 | EXPORT_SYMBOL(tegra_mipi_request); |
| @@ -161,7 +172,7 @@ EXPORT_SYMBOL(tegra_mipi_free); | |||
| 161 | static int tegra_mipi_wait(struct tegra_mipi *mipi) | 172 | static int tegra_mipi_wait(struct tegra_mipi *mipi) |
| 162 | { | 173 | { |
| 163 | unsigned long timeout = jiffies + msecs_to_jiffies(250); | 174 | unsigned long timeout = jiffies + msecs_to_jiffies(250); |
| 164 | unsigned long value; | 175 | u32 value; |
| 165 | 176 | ||
| 166 | while (time_before(jiffies, timeout)) { | 177 | while (time_before(jiffies, timeout)) { |
| 167 | value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); | 178 | value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); |
| @@ -177,8 +188,9 @@ static int tegra_mipi_wait(struct tegra_mipi *mipi) | |||
| 177 | 188 | ||
| 178 | int tegra_mipi_calibrate(struct tegra_mipi_device *device) | 189 | int tegra_mipi_calibrate(struct tegra_mipi_device *device) |
| 179 | { | 190 | { |
| 180 | unsigned long value; | 191 | const struct tegra_mipi_soc *soc = device->mipi->soc; |
| 181 | unsigned int i; | 192 | unsigned int i; |
| 193 | u32 value; | ||
| 182 | int err; | 194 | int err; |
| 183 | 195 | ||
| 184 | err = clk_enable(device->mipi->clk); | 196 | err = clk_enable(device->mipi->clk); |
| @@ -192,23 +204,35 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device) | |||
| 192 | value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; | 204 | value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; |
| 193 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); | 205 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); |
| 194 | 206 | ||
| 207 | tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_DRV_DN_REF(2), | ||
| 208 | MIPI_CAL_BIAS_PAD_CFG1); | ||
| 209 | |||
| 195 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); | 210 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); |
| 196 | value &= ~MIPI_CAL_BIAS_PAD_PDVREG; | 211 | value &= ~MIPI_CAL_BIAS_PAD_PDVREG; |
| 197 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); | 212 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); |
| 198 | 213 | ||
| 199 | for (i = 0; i < ARRAY_SIZE(modules); i++) { | 214 | for (i = 0; i < soc->num_pads; i++) { |
| 200 | if (device->pads & BIT(i)) | 215 | u32 clk = 0, data = 0; |
| 201 | value = MIPI_CAL_CONFIG_SELECT | | 216 | |
| 202 | MIPI_CAL_CONFIG_HSPDOS(0) | | 217 | if (device->pads & BIT(i)) { |
| 203 | MIPI_CAL_CONFIG_HSPUOS(4) | | 218 | data = MIPI_CAL_CONFIG_SELECT | |
| 204 | MIPI_CAL_CONFIG_TERMOS(5); | 219 | MIPI_CAL_CONFIG_HSPDOS(0) | |
| 205 | else | 220 | MIPI_CAL_CONFIG_HSPUOS(4) | |
| 206 | value = 0; | 221 | MIPI_CAL_CONFIG_TERMOS(5); |
| 222 | clk = MIPI_CAL_CONFIG_SELECT | | ||
| 223 | MIPI_CAL_CONFIG_HSCLKPDOSD(0) | | ||
| 224 | MIPI_CAL_CONFIG_HSCLKPUOSD(4); | ||
| 225 | } | ||
| 207 | 226 | ||
| 208 | tegra_mipi_writel(device->mipi, value, modules[i].reg); | 227 | tegra_mipi_writel(device->mipi, data, soc->pads[i].data); |
| 228 | |||
| 229 | if (soc->has_clk_lane) | ||
| 230 | tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk); | ||
| 209 | } | 231 | } |
| 210 | 232 | ||
| 211 | tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL); | 233 | value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL); |
| 234 | value |= MIPI_CAL_CTRL_START; | ||
| 235 | tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL); | ||
| 212 | 236 | ||
| 213 | err = tegra_mipi_wait(device->mipi); | 237 | err = tegra_mipi_wait(device->mipi); |
| 214 | 238 | ||
| @@ -219,16 +243,63 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device) | |||
| 219 | } | 243 | } |
| 220 | EXPORT_SYMBOL(tegra_mipi_calibrate); | 244 | EXPORT_SYMBOL(tegra_mipi_calibrate); |
| 221 | 245 | ||
| 246 | static const struct tegra_mipi_pad tegra114_mipi_pads[] = { | ||
| 247 | { .data = MIPI_CAL_CONFIG_CSIA }, | ||
| 248 | { .data = MIPI_CAL_CONFIG_CSIB }, | ||
| 249 | { .data = MIPI_CAL_CONFIG_CSIC }, | ||
| 250 | { .data = MIPI_CAL_CONFIG_CSID }, | ||
| 251 | { .data = MIPI_CAL_CONFIG_CSIE }, | ||
| 252 | { .data = MIPI_CAL_CONFIG_DSIA }, | ||
| 253 | { .data = MIPI_CAL_CONFIG_DSIB }, | ||
| 254 | { .data = MIPI_CAL_CONFIG_DSIC }, | ||
| 255 | { .data = MIPI_CAL_CONFIG_DSID }, | ||
| 256 | }; | ||
| 257 | |||
| 258 | static const struct tegra_mipi_soc tegra114_mipi_soc = { | ||
| 259 | .has_clk_lane = false, | ||
| 260 | .pads = tegra114_mipi_pads, | ||
| 261 | .num_pads = ARRAY_SIZE(tegra114_mipi_pads), | ||
| 262 | }; | ||
| 263 | |||
| 264 | static const struct tegra_mipi_pad tegra124_mipi_pads[] = { | ||
| 265 | { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, | ||
| 266 | { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK }, | ||
| 267 | { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, | ||
| 268 | { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK }, | ||
| 269 | { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK }, | ||
| 270 | { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK }, | ||
| 271 | { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK }, | ||
| 272 | }; | ||
| 273 | |||
| 274 | static const struct tegra_mipi_soc tegra124_mipi_soc = { | ||
| 275 | .has_clk_lane = true, | ||
| 276 | .pads = tegra124_mipi_pads, | ||
| 277 | .num_pads = ARRAY_SIZE(tegra124_mipi_pads), | ||
| 278 | }; | ||
| 279 | |||
| 280 | static struct of_device_id tegra_mipi_of_match[] = { | ||
| 281 | { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc }, | ||
| 282 | { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc }, | ||
| 283 | { }, | ||
| 284 | }; | ||
| 285 | |||
| 222 | static int tegra_mipi_probe(struct platform_device *pdev) | 286 | static int tegra_mipi_probe(struct platform_device *pdev) |
| 223 | { | 287 | { |
| 288 | const struct of_device_id *match; | ||
| 224 | struct tegra_mipi *mipi; | 289 | struct tegra_mipi *mipi; |
| 225 | struct resource *res; | 290 | struct resource *res; |
| 226 | int err; | 291 | int err; |
| 227 | 292 | ||
| 293 | match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node); | ||
| 294 | if (!match) | ||
| 295 | return -ENODEV; | ||
| 296 | |||
| 228 | mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); | 297 | mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); |
| 229 | if (!mipi) | 298 | if (!mipi) |
| 230 | return -ENOMEM; | 299 | return -ENOMEM; |
| 231 | 300 | ||
| 301 | mipi->soc = match->data; | ||
| 302 | |||
| 232 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 303 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 233 | mipi->regs = devm_ioremap_resource(&pdev->dev, res); | 304 | mipi->regs = devm_ioremap_resource(&pdev->dev, res); |
| 234 | if (IS_ERR(mipi->regs)) | 305 | if (IS_ERR(mipi->regs)) |
| @@ -260,11 +331,6 @@ static int tegra_mipi_remove(struct platform_device *pdev) | |||
| 260 | return 0; | 331 | return 0; |
| 261 | } | 332 | } |
| 262 | 333 | ||
| 263 | static struct of_device_id tegra_mipi_of_match[] = { | ||
| 264 | { .compatible = "nvidia,tegra114-mipi", }, | ||
| 265 | { }, | ||
| 266 | }; | ||
| 267 | |||
| 268 | struct platform_driver tegra_mipi_driver = { | 334 | struct platform_driver tegra_mipi_driver = { |
| 269 | .driver = { | 335 | .driver = { |
| 270 | .name = "tegra-mipi", | 336 | .name = "tegra-mipi", |
