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