Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Ingenic SoCs TCU IRQ driver
0004  * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
0005  * Copyright (C) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
0006  */
0007 
0008 #include <linux/bitops.h>
0009 #include <linux/clk.h>
0010 #include <linux/clockchips.h>
0011 #include <linux/clocksource.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/mfd/ingenic-tcu.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/of.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_irq.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/overflow.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/regmap.h>
0022 #include <linux/sched_clock.h>
0023 
0024 #include <dt-bindings/clock/ingenic,tcu.h>
0025 
0026 static DEFINE_PER_CPU(call_single_data_t, ingenic_cevt_csd);
0027 
0028 struct ingenic_soc_info {
0029     unsigned int num_channels;
0030 };
0031 
0032 struct ingenic_tcu_timer {
0033     unsigned int cpu;
0034     unsigned int channel;
0035     struct clock_event_device cevt;
0036     struct clk *clk;
0037     char name[8];
0038 };
0039 
0040 struct ingenic_tcu {
0041     struct regmap *map;
0042     struct device_node *np;
0043     struct clk *cs_clk;
0044     unsigned int cs_channel;
0045     struct clocksource cs;
0046     unsigned long pwm_channels_mask;
0047     struct ingenic_tcu_timer timers[];
0048 };
0049 
0050 static struct ingenic_tcu *ingenic_tcu;
0051 
0052 static u64 notrace ingenic_tcu_timer_read(void)
0053 {
0054     struct ingenic_tcu *tcu = ingenic_tcu;
0055     unsigned int count;
0056 
0057     regmap_read(tcu->map, TCU_REG_TCNTc(tcu->cs_channel), &count);
0058 
0059     return count;
0060 }
0061 
0062 static u64 notrace ingenic_tcu_timer_cs_read(struct clocksource *cs)
0063 {
0064     return ingenic_tcu_timer_read();
0065 }
0066 
0067 static inline struct ingenic_tcu *
0068 to_ingenic_tcu(struct ingenic_tcu_timer *timer)
0069 {
0070     return container_of(timer, struct ingenic_tcu, timers[timer->cpu]);
0071 }
0072 
0073 static inline struct ingenic_tcu_timer *
0074 to_ingenic_tcu_timer(struct clock_event_device *evt)
0075 {
0076     return container_of(evt, struct ingenic_tcu_timer, cevt);
0077 }
0078 
0079 static int ingenic_tcu_cevt_set_state_shutdown(struct clock_event_device *evt)
0080 {
0081     struct ingenic_tcu_timer *timer = to_ingenic_tcu_timer(evt);
0082     struct ingenic_tcu *tcu = to_ingenic_tcu(timer);
0083 
0084     regmap_write(tcu->map, TCU_REG_TECR, BIT(timer->channel));
0085 
0086     return 0;
0087 }
0088 
0089 static int ingenic_tcu_cevt_set_next(unsigned long next,
0090                      struct clock_event_device *evt)
0091 {
0092     struct ingenic_tcu_timer *timer = to_ingenic_tcu_timer(evt);
0093     struct ingenic_tcu *tcu = to_ingenic_tcu(timer);
0094 
0095     if (next > 0xffff)
0096         return -EINVAL;
0097 
0098     regmap_write(tcu->map, TCU_REG_TDFRc(timer->channel), next);
0099     regmap_write(tcu->map, TCU_REG_TCNTc(timer->channel), 0);
0100     regmap_write(tcu->map, TCU_REG_TESR, BIT(timer->channel));
0101 
0102     return 0;
0103 }
0104 
0105 static void ingenic_per_cpu_event_handler(void *info)
0106 {
0107     struct clock_event_device *cevt = (struct clock_event_device *) info;
0108 
0109     cevt->event_handler(cevt);
0110 }
0111 
0112 static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id)
0113 {
0114     struct ingenic_tcu_timer *timer = dev_id;
0115     struct ingenic_tcu *tcu = to_ingenic_tcu(timer);
0116     call_single_data_t *csd;
0117 
0118     regmap_write(tcu->map, TCU_REG_TECR, BIT(timer->channel));
0119 
0120     if (timer->cevt.event_handler) {
0121         csd = &per_cpu(ingenic_cevt_csd, timer->cpu);
0122         csd->info = (void *) &timer->cevt;
0123         csd->func = ingenic_per_cpu_event_handler;
0124         smp_call_function_single_async(timer->cpu, csd);
0125     }
0126 
0127     return IRQ_HANDLED;
0128 }
0129 
0130 static struct clk *ingenic_tcu_get_clock(struct device_node *np, int id)
0131 {
0132     struct of_phandle_args args;
0133 
0134     args.np = np;
0135     args.args_count = 1;
0136     args.args[0] = id;
0137 
0138     return of_clk_get_from_provider(&args);
0139 }
0140 
0141 static int ingenic_tcu_setup_cevt(unsigned int cpu)
0142 {
0143     struct ingenic_tcu *tcu = ingenic_tcu;
0144     struct ingenic_tcu_timer *timer = &tcu->timers[cpu];
0145     unsigned int timer_virq;
0146     struct irq_domain *domain;
0147     unsigned long rate;
0148     int err;
0149 
0150     timer->clk = ingenic_tcu_get_clock(tcu->np, timer->channel);
0151     if (IS_ERR(timer->clk))
0152         return PTR_ERR(timer->clk);
0153 
0154     err = clk_prepare_enable(timer->clk);
0155     if (err)
0156         goto err_clk_put;
0157 
0158     rate = clk_get_rate(timer->clk);
0159     if (!rate) {
0160         err = -EINVAL;
0161         goto err_clk_disable;
0162     }
0163 
0164     domain = irq_find_host(tcu->np);
0165     if (!domain) {
0166         err = -ENODEV;
0167         goto err_clk_disable;
0168     }
0169 
0170     timer_virq = irq_create_mapping(domain, timer->channel);
0171     if (!timer_virq) {
0172         err = -EINVAL;
0173         goto err_clk_disable;
0174     }
0175 
0176     snprintf(timer->name, sizeof(timer->name), "TCU%u", timer->channel);
0177 
0178     err = request_irq(timer_virq, ingenic_tcu_cevt_cb, IRQF_TIMER,
0179               timer->name, timer);
0180     if (err)
0181         goto err_irq_dispose_mapping;
0182 
0183     timer->cpu = smp_processor_id();
0184     timer->cevt.cpumask = cpumask_of(smp_processor_id());
0185     timer->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
0186     timer->cevt.name = timer->name;
0187     timer->cevt.rating = 200;
0188     timer->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown;
0189     timer->cevt.set_next_event = ingenic_tcu_cevt_set_next;
0190 
0191     clockevents_config_and_register(&timer->cevt, rate, 10, 0xffff);
0192 
0193     return 0;
0194 
0195 err_irq_dispose_mapping:
0196     irq_dispose_mapping(timer_virq);
0197 err_clk_disable:
0198     clk_disable_unprepare(timer->clk);
0199 err_clk_put:
0200     clk_put(timer->clk);
0201     return err;
0202 }
0203 
0204 static int __init ingenic_tcu_clocksource_init(struct device_node *np,
0205                            struct ingenic_tcu *tcu)
0206 {
0207     unsigned int channel = tcu->cs_channel;
0208     struct clocksource *cs = &tcu->cs;
0209     unsigned long rate;
0210     int err;
0211 
0212     tcu->cs_clk = ingenic_tcu_get_clock(np, channel);
0213     if (IS_ERR(tcu->cs_clk))
0214         return PTR_ERR(tcu->cs_clk);
0215 
0216     err = clk_prepare_enable(tcu->cs_clk);
0217     if (err)
0218         goto err_clk_put;
0219 
0220     rate = clk_get_rate(tcu->cs_clk);
0221     if (!rate) {
0222         err = -EINVAL;
0223         goto err_clk_disable;
0224     }
0225 
0226     /* Reset channel */
0227     regmap_update_bits(tcu->map, TCU_REG_TCSRc(channel),
0228                0xffff & ~TCU_TCSR_RESERVED_BITS, 0);
0229 
0230     /* Reset counter */
0231     regmap_write(tcu->map, TCU_REG_TDFRc(channel), 0xffff);
0232     regmap_write(tcu->map, TCU_REG_TCNTc(channel), 0);
0233 
0234     /* Enable channel */
0235     regmap_write(tcu->map, TCU_REG_TESR, BIT(channel));
0236 
0237     cs->name = "ingenic-timer";
0238     cs->rating = 200;
0239     cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
0240     cs->mask = CLOCKSOURCE_MASK(16);
0241     cs->read = ingenic_tcu_timer_cs_read;
0242 
0243     err = clocksource_register_hz(cs, rate);
0244     if (err)
0245         goto err_clk_disable;
0246 
0247     return 0;
0248 
0249 err_clk_disable:
0250     clk_disable_unprepare(tcu->cs_clk);
0251 err_clk_put:
0252     clk_put(tcu->cs_clk);
0253     return err;
0254 }
0255 
0256 static const struct ingenic_soc_info jz4740_soc_info = {
0257     .num_channels = 8,
0258 };
0259 
0260 static const struct ingenic_soc_info jz4725b_soc_info = {
0261     .num_channels = 6,
0262 };
0263 
0264 static const struct of_device_id ingenic_tcu_of_match[] = {
0265     { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
0266     { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
0267     { .compatible = "ingenic,jz4760-tcu", .data = &jz4740_soc_info, },
0268     { .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, },
0269     { .compatible = "ingenic,x1000-tcu", .data = &jz4740_soc_info, },
0270     { /* sentinel */ }
0271 };
0272 
0273 static int __init ingenic_tcu_init(struct device_node *np)
0274 {
0275     const struct of_device_id *id = of_match_node(ingenic_tcu_of_match, np);
0276     const struct ingenic_soc_info *soc_info = id->data;
0277     struct ingenic_tcu_timer *timer;
0278     struct ingenic_tcu *tcu;
0279     struct regmap *map;
0280     unsigned int cpu;
0281     int ret, last_bit = -1;
0282     long rate;
0283 
0284     of_node_clear_flag(np, OF_POPULATED);
0285 
0286     map = device_node_to_regmap(np);
0287     if (IS_ERR(map))
0288         return PTR_ERR(map);
0289 
0290     tcu = kzalloc(struct_size(tcu, timers, num_possible_cpus()),
0291               GFP_KERNEL);
0292     if (!tcu)
0293         return -ENOMEM;
0294 
0295     /*
0296      * Enable all TCU channels for PWM use by default except channels 0/1,
0297      * and channel 2 if target CPU is JZ4780/X2000 and SMP is selected.
0298      */
0299     tcu->pwm_channels_mask = GENMASK(soc_info->num_channels - 1,
0300                      num_possible_cpus() + 1);
0301     of_property_read_u32(np, "ingenic,pwm-channels-mask",
0302                  (u32 *)&tcu->pwm_channels_mask);
0303 
0304     /* Verify that we have at least num_possible_cpus() + 1 free channels */
0305     if (hweight8(tcu->pwm_channels_mask) >
0306             soc_info->num_channels - num_possible_cpus() + 1) {
0307         pr_crit("%s: Invalid PWM channel mask: 0x%02lx\n", __func__,
0308             tcu->pwm_channels_mask);
0309         ret = -EINVAL;
0310         goto err_free_ingenic_tcu;
0311     }
0312 
0313     tcu->map = map;
0314     tcu->np = np;
0315     ingenic_tcu = tcu;
0316 
0317     for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
0318         timer = &tcu->timers[cpu];
0319 
0320         timer->cpu = cpu;
0321         timer->channel = find_next_zero_bit(&tcu->pwm_channels_mask,
0322                           soc_info->num_channels,
0323                           last_bit + 1);
0324         last_bit = timer->channel;
0325     }
0326 
0327     tcu->cs_channel = find_next_zero_bit(&tcu->pwm_channels_mask,
0328                          soc_info->num_channels,
0329                          last_bit + 1);
0330 
0331     ret = ingenic_tcu_clocksource_init(np, tcu);
0332     if (ret) {
0333         pr_crit("%s: Unable to init clocksource: %d\n", __func__, ret);
0334         goto err_free_ingenic_tcu;
0335     }
0336 
0337     /* Setup clock events on each CPU core */
0338     ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "Ingenic XBurst: online",
0339                 ingenic_tcu_setup_cevt, NULL);
0340     if (ret < 0) {
0341         pr_crit("%s: Unable to start CPU timers: %d\n", __func__, ret);
0342         goto err_tcu_clocksource_cleanup;
0343     }
0344 
0345     /* Register the sched_clock at the end as there's no way to undo it */
0346     rate = clk_get_rate(tcu->cs_clk);
0347     sched_clock_register(ingenic_tcu_timer_read, 16, rate);
0348 
0349     return 0;
0350 
0351 err_tcu_clocksource_cleanup:
0352     clocksource_unregister(&tcu->cs);
0353     clk_disable_unprepare(tcu->cs_clk);
0354     clk_put(tcu->cs_clk);
0355 err_free_ingenic_tcu:
0356     kfree(tcu);
0357     return ret;
0358 }
0359 
0360 TIMER_OF_DECLARE(jz4740_tcu_intc,  "ingenic,jz4740-tcu",  ingenic_tcu_init);
0361 TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init);
0362 TIMER_OF_DECLARE(jz4760_tcu_intc,  "ingenic,jz4760-tcu",  ingenic_tcu_init);
0363 TIMER_OF_DECLARE(jz4770_tcu_intc,  "ingenic,jz4770-tcu",  ingenic_tcu_init);
0364 TIMER_OF_DECLARE(x1000_tcu_intc,  "ingenic,x1000-tcu",  ingenic_tcu_init);
0365 
0366 static int __init ingenic_tcu_probe(struct platform_device *pdev)
0367 {
0368     platform_set_drvdata(pdev, ingenic_tcu);
0369 
0370     return 0;
0371 }
0372 
0373 static int __maybe_unused ingenic_tcu_suspend(struct device *dev)
0374 {
0375     struct ingenic_tcu *tcu = dev_get_drvdata(dev);
0376     unsigned int cpu;
0377 
0378     clk_disable(tcu->cs_clk);
0379 
0380     for (cpu = 0; cpu < num_online_cpus(); cpu++)
0381         clk_disable(tcu->timers[cpu].clk);
0382 
0383     return 0;
0384 }
0385 
0386 static int __maybe_unused ingenic_tcu_resume(struct device *dev)
0387 {
0388     struct ingenic_tcu *tcu = dev_get_drvdata(dev);
0389     unsigned int cpu;
0390     int ret;
0391 
0392     for (cpu = 0; cpu < num_online_cpus(); cpu++) {
0393         ret = clk_enable(tcu->timers[cpu].clk);
0394         if (ret)
0395             goto err_timer_clk_disable;
0396     }
0397 
0398     ret = clk_enable(tcu->cs_clk);
0399     if (ret)
0400         goto err_timer_clk_disable;
0401 
0402     return 0;
0403 
0404 err_timer_clk_disable:
0405     for (; cpu > 0; cpu--)
0406         clk_disable(tcu->timers[cpu - 1].clk);
0407     return ret;
0408 }
0409 
0410 static const struct dev_pm_ops __maybe_unused ingenic_tcu_pm_ops = {
0411     /* _noirq: We want the TCU clocks to be gated last / ungated first */
0412     .suspend_noirq = ingenic_tcu_suspend,
0413     .resume_noirq  = ingenic_tcu_resume,
0414 };
0415 
0416 static struct platform_driver ingenic_tcu_driver = {
0417     .driver = {
0418         .name   = "ingenic-tcu-timer",
0419 #ifdef CONFIG_PM_SLEEP
0420         .pm = &ingenic_tcu_pm_ops,
0421 #endif
0422         .of_match_table = ingenic_tcu_of_match,
0423     },
0424 };
0425 builtin_platform_driver_probe(ingenic_tcu_driver, ingenic_tcu_probe);