kernel: bump 4.14 to 4.14.107
[openwrt/openwrt.git] / target / linux / layerscape / patches-4.14 / 803-flextimer-support-layerscape.patch
1 From d586effc9b71ddf240fb294b1ab1205bbe6fec4b Mon Sep 17 00:00:00 2001
2 From: Biwen Li <biwen.li@nxp.com>
3 Date: Tue, 30 Oct 2018 18:26:32 +0800
4 Subject: [PATCH 20/40] flextimer: support layerscape
5 This is an integrated patch of flextimer for layerscape
6
7 Signed-off-by: Meng Yi <meng.yi@nxp.com>
8 Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
9 Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
10 Signed-off-by: Biwen Li <biwen.li@nxp.com>
11 ---
12 .../bindings/soc/fsl/layerscape/ftm-alarm.txt | 32 ++
13 drivers/clocksource/fsl_ftm_timer.c | 8 +-
14 drivers/soc/fsl/layerscape/ftm_alarm.c | 375 ++++++++++++++++++
15 3 files changed, 411 insertions(+), 4 deletions(-)
16 create mode 100644 Documentation/devicetree/bindings/soc/fsl/layerscape/ftm-alarm.txt
17 create mode 100644 drivers/soc/fsl/layerscape/ftm_alarm.c
18
19 --- /dev/null
20 +++ b/Documentation/devicetree/bindings/soc/fsl/layerscape/ftm-alarm.txt
21 @@ -0,0 +1,32 @@
22 +Freescale FlexTimer Module (FTM) Alarm
23 +
24 +Required properties:
25 +
26 +- compatible : Should be "fsl,ftm-alarm" or "fsl,<chip>-ftm-alarm", the
27 + supported chips include
28 + "fsl,ls1012a-ftm-alarm"
29 + "fsl,ls1021a-ftm-alarm"
30 + "fsl,ls1043a-ftm-alarm"
31 + "fsl,ls1046a-ftm-alarm"
32 + "fsl,ls1088a-ftm-alarm"
33 + "fsl,ls208xa-ftm-alarm"
34 +- reg : Specifies base physical address and size of the register sets for the
35 + FlexTimer Module and base physical address of IP Powerdown Exception Control
36 + Register.
37 +- reg-names: names of the mapped memory regions listed in regs property.
38 + should include the following entries:
39 + "ftm": Address of the register sets for FlexTimer Module
40 + "pmctrl": Address of IP Powerdown Exception Control register
41 +- interrupts : Should be the FlexTimer Module interrupt.
42 +- big-endian: If the host controller is big-endian mode, specify this property.
43 + The default endian mode is little-endian.
44 +
45 +Example:
46 +ftm0: ftm0@29d0000 {
47 + compatible = "fsl,ls1043a-ftm-alarm";
48 + reg = <0x0 0x29d0000 0x0 0x10000>,
49 + <0x0 0x1ee2140 0x0 0x4>;
50 + reg-names = "ftm", "pmctrl";
51 + interrupts = <0 86 0x4>;
52 + big-endian;
53 +};
54 --- a/drivers/clocksource/fsl_ftm_timer.c
55 +++ b/drivers/clocksource/fsl_ftm_timer.c
56 @@ -83,11 +83,11 @@ static inline void ftm_counter_disable(v
57
58 static inline void ftm_irq_acknowledge(void __iomem *base)
59 {
60 - u32 val;
61 + unsigned int timeout = 100;
62
63 - val = ftm_readl(base + FTM_SC);
64 - val &= ~FTM_SC_TOF;
65 - ftm_writel(val, base + FTM_SC);
66 + while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
67 + ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
68 + base + FTM_SC);
69 }
70
71 static inline void ftm_irq_enable(void __iomem *base)
72 --- /dev/null
73 +++ b/drivers/soc/fsl/layerscape/ftm_alarm.c
74 @@ -0,0 +1,375 @@
75 +/*
76 + * Freescale FlexTimer Module (FTM) Alarm driver.
77 + *
78 + * Copyright 2014 Freescale Semiconductor, Inc.
79 + *
80 + * This program is free software; you can redistribute it and/or
81 + * modify it under the terms of the GNU General Public License
82 + * as published by the Free Software Foundation; either version 2
83 + * of the License, or (at your option) any later version.
84 + */
85 +
86 +#include <linux/device.h>
87 +#include <linux/err.h>
88 +#include <linux/interrupt.h>
89 +#include <linux/io.h>
90 +#include <linux/of_address.h>
91 +#include <linux/of_irq.h>
92 +#include <linux/platform_device.h>
93 +#include <linux/of.h>
94 +#include <linux/of_device.h>
95 +#include <linux/libata.h>
96 +#include <linux/module.h>
97 +
98 +#define FTM_SC 0x00
99 +#define FTM_SC_CLK_SHIFT 3
100 +#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
101 +#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
102 +#define FTM_SC_PS_MASK 0x7
103 +#define FTM_SC_TOIE BIT(6)
104 +#define FTM_SC_TOF BIT(7)
105 +
106 +#define FTM_SC_CLKS_FIXED_FREQ 0x02
107 +
108 +#define FTM_CNT 0x04
109 +#define FTM_MOD 0x08
110 +#define FTM_CNTIN 0x4C
111 +
112 +#define FIXED_FREQ_CLK 32000
113 +#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK)
114 +#define MAX_COUNT_VAL 0xffff
115 +
116 +static void __iomem *ftm1_base;
117 +static void __iomem *rcpm_ftm_addr;
118 +static void __iomem *scfg_scrachpad_addr;
119 +static u32 alarm_freq;
120 +static bool big_endian;
121 +
122 +enum pmu_endian_type {
123 + BIG_ENDIAN,
124 + LITTLE_ENDIAN,
125 +};
126 +
127 +struct rcpm_cfg {
128 + enum pmu_endian_type big_endian; /* Big/Little endian of PMU module */
129 + u32 flextimer_set_bit; /* FTM is not powerdown during device LPM20 */
130 +};
131 +
132 +static struct rcpm_cfg ls1012a_rcpm_cfg = {
133 + .big_endian = BIG_ENDIAN,
134 + .flextimer_set_bit = 0x20000,
135 +};
136 +
137 +static struct rcpm_cfg ls1021a_rcpm_cfg = {
138 + .big_endian = BIG_ENDIAN,
139 + .flextimer_set_bit = 0x30000000,
140 +};
141 +
142 +static struct rcpm_cfg ls1043a_rcpm_cfg = {
143 + .big_endian = BIG_ENDIAN,
144 + .flextimer_set_bit = 0x20000,
145 +};
146 +
147 +static struct rcpm_cfg ls1046a_rcpm_cfg = {
148 + .big_endian = BIG_ENDIAN,
149 + .flextimer_set_bit = 0x20000,
150 +};
151 +
152 +static struct rcpm_cfg ls1088a_rcpm_cfg = {
153 + .big_endian = LITTLE_ENDIAN,
154 + .flextimer_set_bit = 0x4000,
155 +};
156 +
157 +static struct rcpm_cfg ls208xa_rcpm_cfg = {
158 + .big_endian = LITTLE_ENDIAN,
159 + .flextimer_set_bit = 0x4000,
160 +};
161 +
162 +static const struct of_device_id ippdexpcr_of_match[] = {
163 + { .compatible = "fsl,ls1012a-ftm-alarm", .data = &ls1012a_rcpm_cfg},
164 + { .compatible = "fsl,ls1021a-ftm-alarm", .data = &ls1021a_rcpm_cfg},
165 + { .compatible = "fsl,ls1043a-ftm-alarm", .data = &ls1043a_rcpm_cfg},
166 + { .compatible = "fsl,ls1046a-ftm-alarm", .data = &ls1046a_rcpm_cfg},
167 + { .compatible = "fsl,ls1088a-ftm-alarm", .data = &ls1088a_rcpm_cfg},
168 + { .compatible = "fsl,ls208xa-ftm-alarm", .data = &ls208xa_rcpm_cfg},
169 + {},
170 +};
171 +MODULE_DEVICE_TABLE(of, ippdexpcr_of_match);
172 +
173 +static inline u32 ftm_readl(void __iomem *addr)
174 +{
175 + if (big_endian)
176 + return ioread32be(addr);
177 +
178 + return ioread32(addr);
179 +}
180 +
181 +static inline void ftm_writel(u32 val, void __iomem *addr)
182 +{
183 + if (big_endian)
184 + iowrite32be(val, addr);
185 + else
186 + iowrite32(val, addr);
187 +}
188 +
189 +static inline void ftm_counter_enable(void __iomem *base)
190 +{
191 + u32 val;
192 +
193 + /* select and enable counter clock source */
194 + val = ftm_readl(base + FTM_SC);
195 + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
196 + val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
197 + ftm_writel(val, base + FTM_SC);
198 +}
199 +
200 +static inline void ftm_counter_disable(void __iomem *base)
201 +{
202 + u32 val;
203 +
204 + /* disable counter clock source */
205 + val = ftm_readl(base + FTM_SC);
206 + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
207 + ftm_writel(val, base + FTM_SC);
208 +}
209 +
210 +static inline void ftm_irq_acknowledge(void __iomem *base)
211 +{
212 + unsigned int timeout = 100;
213 +
214 + while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
215 + ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
216 + base + FTM_SC);
217 +}
218 +
219 +static inline void ftm_irq_enable(void __iomem *base)
220 +{
221 + u32 val;
222 +
223 + val = ftm_readl(base + FTM_SC);
224 + val |= FTM_SC_TOIE;
225 + ftm_writel(val, base + FTM_SC);
226 +}
227 +
228 +static inline void ftm_irq_disable(void __iomem *base)
229 +{
230 + u32 val;
231 +
232 + val = ftm_readl(base + FTM_SC);
233 + val &= ~FTM_SC_TOIE;
234 + ftm_writel(val, base + FTM_SC);
235 +}
236 +
237 +static inline void ftm_reset_counter(void __iomem *base)
238 +{
239 + /*
240 + * The CNT register contains the FTM counter value.
241 + * Reset clears the CNT register. Writing any value to COUNT
242 + * updates the counter with its initial value, CNTIN.
243 + */
244 + ftm_writel(0x00, base + FTM_CNT);
245 +}
246 +
247 +static u32 time_to_cycle(unsigned long time)
248 +{
249 + u32 cycle;
250 +
251 + cycle = time * alarm_freq;
252 + if (cycle > MAX_COUNT_VAL) {
253 + pr_err("Out of alarm range.\n");
254 + cycle = 0;
255 + }
256 +
257 + return cycle;
258 +}
259 +
260 +static u32 cycle_to_time(u32 cycle)
261 +{
262 + return cycle / alarm_freq + 1;
263 +}
264 +
265 +static void ftm_clean_alarm(void)
266 +{
267 + ftm_counter_disable(ftm1_base);
268 +
269 + ftm_writel(0x00, ftm1_base + FTM_CNTIN);
270 + ftm_writel(~0U, ftm1_base + FTM_MOD);
271 +
272 + ftm_reset_counter(ftm1_base);
273 +}
274 +
275 +static int ftm_set_alarm(u64 cycle)
276 +{
277 + ftm_irq_disable(ftm1_base);
278 +
279 + /*
280 + * The counter increments until the value of MOD is reached,
281 + * at which point the counter is reloaded with the value of CNTIN.
282 + * The TOF (the overflow flag) bit is set when the FTM counter
283 + * changes from MOD to CNTIN. So we should using the cycle - 1.
284 + */
285 + ftm_writel(cycle - 1, ftm1_base + FTM_MOD);
286 +
287 + ftm_counter_enable(ftm1_base);
288 +
289 + ftm_irq_enable(ftm1_base);
290 +
291 + return 0;
292 +}
293 +
294 +static irqreturn_t ftm_alarm_interrupt(int irq, void *dev_id)
295 +{
296 + ftm_irq_acknowledge(ftm1_base);
297 + ftm_irq_disable(ftm1_base);
298 + ftm_clean_alarm();
299 +
300 + return IRQ_HANDLED;
301 +}
302 +
303 +static ssize_t ftm_alarm_show(struct device *dev,
304 + struct device_attribute *attr,
305 + char *buf)
306 +{
307 + u32 count, val;
308 +
309 + count = ftm_readl(ftm1_base + FTM_MOD);
310 + val = ftm_readl(ftm1_base + FTM_CNT);
311 + val = (count & MAX_COUNT_VAL) - val;
312 + val = cycle_to_time(val);
313 +
314 + return sprintf(buf, "%u\n", val);
315 +}
316 +
317 +static ssize_t ftm_alarm_store(struct device *dev,
318 + struct device_attribute *attr,
319 + const char *buf, size_t count)
320 +{
321 + u32 cycle;
322 + unsigned long time;
323 +
324 + if (kstrtoul(buf, 0, &time))
325 + return -EINVAL;
326 +
327 + ftm_clean_alarm();
328 +
329 + cycle = time_to_cycle(time);
330 + if (!cycle)
331 + return -EINVAL;
332 +
333 + ftm_set_alarm(cycle);
334 +
335 + return count;
336 +}
337 +
338 +static struct device_attribute ftm_alarm_attributes = __ATTR(ftm_alarm, 0644,
339 + ftm_alarm_show, ftm_alarm_store);
340 +
341 +static int ftm_alarm_probe(struct platform_device *pdev)
342 +{
343 + struct device_node *np = pdev->dev.of_node;
344 + struct resource *r;
345 + int irq;
346 + int ret;
347 + struct rcpm_cfg *rcpm_cfg;
348 + u32 ippdexpcr, flextimer;
349 + const struct of_device_id *of_id;
350 + enum pmu_endian_type endian;
351 +
352 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
353 + if (!r)
354 + return -ENODEV;
355 +
356 + ftm1_base = devm_ioremap_resource(&pdev->dev, r);
357 + if (IS_ERR(ftm1_base))
358 + return PTR_ERR(ftm1_base);
359 +
360 + of_id = of_match_node(ippdexpcr_of_match, np);
361 + if (!of_id)
362 + return -ENODEV;
363 +
364 + rcpm_cfg = devm_kzalloc(&pdev->dev, sizeof(*rcpm_cfg), GFP_KERNEL);
365 + if (!rcpm_cfg)
366 + return -ENOMEM;
367 +
368 + rcpm_cfg = (struct rcpm_cfg *)of_id->data;
369 + endian = rcpm_cfg->big_endian;
370 + flextimer = rcpm_cfg->flextimer_set_bit;
371 +
372 + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmctrl");
373 + if (r) {
374 + rcpm_ftm_addr = devm_ioremap_resource(&pdev->dev, r);
375 + if (IS_ERR(rcpm_ftm_addr))
376 + return PTR_ERR(rcpm_ftm_addr);
377 + if (endian == BIG_ENDIAN)
378 + ippdexpcr = ioread32be(rcpm_ftm_addr);
379 + else
380 + ippdexpcr = ioread32(rcpm_ftm_addr);
381 + ippdexpcr |= flextimer;
382 + if (endian == BIG_ENDIAN)
383 + iowrite32be(ippdexpcr, rcpm_ftm_addr);
384 + else
385 + iowrite32(ippdexpcr, rcpm_ftm_addr);
386 +
387 + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scrachpad");
388 + if (r) {
389 + scfg_scrachpad_addr = devm_ioremap_resource(&pdev->dev, r);
390 + iowrite32(ippdexpcr, scfg_scrachpad_addr);
391 + }
392 + }
393 +
394 + irq = irq_of_parse_and_map(np, 0);
395 + if (irq <= 0) {
396 + pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
397 + return -EINVAL;
398 + }
399 +
400 + big_endian = of_property_read_bool(np, "big-endian");
401 +
402 + ret = devm_request_irq(&pdev->dev, irq, ftm_alarm_interrupt,
403 + IRQF_NO_SUSPEND, dev_name(&pdev->dev), NULL);
404 + if (ret < 0) {
405 + dev_err(&pdev->dev, "failed to request irq\n");
406 + return ret;
407 + }
408 +
409 + ret = device_create_file(&pdev->dev, &ftm_alarm_attributes);
410 + if (ret) {
411 + dev_err(&pdev->dev, "create sysfs fail.\n");
412 + return ret;
413 + }
414 +
415 + alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
416 +
417 + ftm_clean_alarm();
418 +
419 + device_init_wakeup(&pdev->dev, true);
420 +
421 + return ret;
422 +}
423 +
424 +static const struct of_device_id ftm_alarm_match[] = {
425 + { .compatible = "fsl,ftm-alarm", },
426 + { .compatible = "fsl,ls1012a-ftm-alarm", },
427 + { .compatible = "fsl,ls1021a-ftm-alarm", },
428 + { .compatible = "fsl,ls1043a-ftm-alarm", },
429 + { .compatible = "fsl,ls1046a-ftm-alarm", },
430 + { .compatible = "fsl,ls1088a-ftm-alarm", },
431 + { .compatible = "fsl,ls208xa-ftm-alarm", },
432 + { .compatible = "fsl,ftm-timer", },
433 + { },
434 +};
435 +
436 +static struct platform_driver ftm_alarm_driver = {
437 + .probe = ftm_alarm_probe,
438 + .driver = {
439 + .name = "ftm-alarm",
440 + .owner = THIS_MODULE,
441 + .of_match_table = ftm_alarm_match,
442 + },
443 +};
444 +
445 +static int __init ftm_alarm_init(void)
446 +{
447 + return platform_driver_register(&ftm_alarm_driver);
448 +}
449 +device_initcall(ftm_alarm_init);