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