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", |