Lines Matching refs:cpts
23 #include "am65-cpts.h"
204 static void am65_cpts_settime(struct am65_cpts *cpts, u64 start_tstamp)
209 am65_cpts_write32(cpts, val, ts_load_val_hi);
211 am65_cpts_write32(cpts, val, ts_load_val_lo);
213 am65_cpts_write32(cpts, AM65_CPTS_TS_LOAD_EN, ts_load_en);
216 static void am65_cpts_set_add_val(struct am65_cpts *cpts)
219 cpts->ts_add_val = (NSEC_PER_SEC / cpts->refclk_freq - 1) & 0x7;
221 am65_cpts_write32(cpts, cpts->ts_add_val, ts_add_val);
224 static void am65_cpts_disable(struct am65_cpts *cpts)
226 am65_cpts_write32(cpts, 0, control);
227 am65_cpts_write32(cpts, 0, int_enable);
242 static int am65_cpts_cpts_purge_events(struct am65_cpts *cpts)
248 list_for_each_safe(this, next, &cpts->events) {
252 list_add(&event->list, &cpts->pool);
258 dev_dbg(cpts->dev, "event pool cleaned up %d\n", removed);
262 static bool am65_cpts_fifo_pop_event(struct am65_cpts *cpts,
265 u32 r = am65_cpts_read32(cpts, intstat_raw);
268 event->timestamp = am65_cpts_read32(cpts, event_0);
269 event->event1 = am65_cpts_read32(cpts, event_1);
270 event->event2 = am65_cpts_read32(cpts, event_2);
271 event->timestamp |= (u64)am65_cpts_read32(cpts, event_3) << 32;
272 am65_cpts_write32(cpts, AM65_CPTS_EVENT_POP, event_pop);
278 static int am65_cpts_fifo_read(struct am65_cpts *cpts)
286 spin_lock_irqsave(&cpts->lock, flags);
288 event = list_first_entry_or_null(&cpts->pool,
292 if (am65_cpts_cpts_purge_events(cpts)) {
293 dev_err(cpts->dev, "cpts: event pool empty\n");
300 if (am65_cpts_fifo_pop_event(cpts, event))
306 cpts->timestamp = event->timestamp;
307 dev_dbg(cpts->dev, "AM65_CPTS_EV_PUSH t:%llu\n",
308 cpts->timestamp);
316 list_add_tail(&event->list, &cpts->events);
318 dev_dbg(cpts->dev,
327 if (cpts->pps_enabled && pevent.index == cpts->pps_hw_ts_idx) {
333 dev_dbg(cpts->dev, "AM65_CPTS_EV_HW:%s p:%d t:%llu\n",
338 ptp_clock_event(cpts->ptp_clock, &pevent);
345 dev_dbg(cpts->dev,
352 dev_err(cpts->dev, "cpts: unknown event type\n");
359 spin_unlock_irqrestore(&cpts->lock, flags);
362 ptp_schedule_worker(cpts->ptp_clock, 0);
367 static u64 am65_cpts_gettime(struct am65_cpts *cpts,
373 /* temporarily disable cpts interrupt to avoid intentional
376 am65_cpts_write32(cpts, 0, int_enable);
379 spin_lock_irqsave(&cpts->lock, flags);
381 am65_cpts_write32(cpts, AM65_CPTS_TS_PUSH, ts_push);
382 am65_cpts_read32(cpts, ts_push);
384 spin_unlock_irqrestore(&cpts->lock, flags);
386 am65_cpts_fifo_read(cpts);
388 am65_cpts_write32(cpts, AM65_CPTS_INT_ENABLE_TS_PEND_EN, int_enable);
390 val = cpts->timestamp;
397 struct am65_cpts *cpts = dev_id;
399 if (am65_cpts_fifo_read(cpts))
400 dev_dbg(cpts->dev, "cpts: unable to obtain a time stamp\n");
408 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
411 int pps_index = cpts->pps_genf_idx;
431 adj_period = div_u64(cpts->refclk_freq, ppb);
433 mutex_lock(&cpts->ptp_clk_lock);
435 ctrl_val = am65_cpts_read32(cpts, control);
444 if (cpts->pps_enabled) {
445 estf_ctrl_val = am65_cpts_read32(cpts, genf[pps_index].control);
451 /* GenF PPM will do correction using cpts refclk tick which is
452 * (cpts->ts_add_val + 1) ns, so GenF length PPM adj period
455 pps_adj_period = adj_period * (cpts->ts_add_val + 1);
460 spin_lock_irqsave(&cpts->lock, flags);
470 am65_cpts_write32(cpts, ctrl_val, control);
471 am65_cpts_write32(cpts, ppm_hi, ts_ppm_hi);
472 am65_cpts_write32(cpts, ppm_low, ts_ppm_low);
474 if (cpts->pps_enabled) {
475 am65_cpts_write32(cpts, estf_ctrl_val, genf[pps_index].control);
476 am65_cpts_write32(cpts, estf_ppm_hi, genf[pps_index].ppm_hi);
477 am65_cpts_write32(cpts, estf_ppm_low, genf[pps_index].ppm_low);
481 if (cpts->estf_enable & BIT(i)) {
482 am65_cpts_write32(cpts, estf_ctrl_val, estf[i].control);
483 am65_cpts_write32(cpts, estf_ppm_hi, estf[i].ppm_hi);
484 am65_cpts_write32(cpts, estf_ppm_low, estf[i].ppm_low);
488 spin_unlock_irqrestore(&cpts->lock, flags);
490 mutex_unlock(&cpts->ptp_clk_lock);
497 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
500 mutex_lock(&cpts->ptp_clk_lock);
501 ns = am65_cpts_gettime(cpts, NULL);
503 am65_cpts_settime(cpts, ns);
504 mutex_unlock(&cpts->ptp_clk_lock);
513 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
516 mutex_lock(&cpts->ptp_clk_lock);
517 ns = am65_cpts_gettime(cpts, sts);
518 mutex_unlock(&cpts->ptp_clk_lock);
524 u64 am65_cpts_ns_gettime(struct am65_cpts *cpts)
529 mutex_lock(&cpts->ptp_clk_lock);
530 ns = am65_cpts_gettime(cpts, NULL);
531 mutex_unlock(&cpts->ptp_clk_lock);
540 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
544 mutex_lock(&cpts->ptp_clk_lock);
545 am65_cpts_settime(cpts, ns);
546 mutex_unlock(&cpts->ptp_clk_lock);
551 static void am65_cpts_extts_enable_hw(struct am65_cpts *cpts, u32 index, int on)
555 v = am65_cpts_read32(cpts, control);
558 cpts->hw_ts_enable |= BIT(index);
561 cpts->hw_ts_enable &= ~BIT(index);
563 am65_cpts_write32(cpts, v, control);
566 static int am65_cpts_extts_enable(struct am65_cpts *cpts, u32 index, int on)
568 if (index >= cpts->ptp_info.n_ext_ts)
571 if (cpts->pps_present && index == cpts->pps_hw_ts_idx)
574 if (((cpts->hw_ts_enable & BIT(index)) >> index) == on)
577 mutex_lock(&cpts->ptp_clk_lock);
578 am65_cpts_extts_enable_hw(cpts, index, on);
579 mutex_unlock(&cpts->ptp_clk_lock);
581 dev_dbg(cpts->dev, "%s: ExtTS:%u %s\n",
587 int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
593 cycles = cfg->ns_period * cpts->refclk_freq;
599 am65_cpts_write32(cpts, 0, estf[idx].length);
602 am65_cpts_write32(cpts, val, estf[idx].comp_hi);
604 am65_cpts_write32(cpts, val, estf[idx].comp_lo);
606 am65_cpts_write32(cpts, val, estf[idx].length);
607 am65_cpts_write32(cpts, 0, estf[idx].control);
608 am65_cpts_write32(cpts, 0, estf[idx].ppm_hi);
609 am65_cpts_write32(cpts, 0, estf[idx].ppm_low);
611 cpts->estf_enable |= BIT(idx);
613 dev_dbg(cpts->dev, "%s: ESTF:%u enabled\n", __func__, idx);
619 void am65_cpts_estf_disable(struct am65_cpts *cpts, int idx)
621 am65_cpts_write32(cpts, 0, estf[idx].length);
622 cpts->estf_enable &= ~BIT(idx);
624 dev_dbg(cpts->dev, "%s: ESTF:%u disabled\n", __func__, idx);
628 static void am65_cpts_perout_enable_hw(struct am65_cpts *cpts,
640 cycles = (ns_period * cpts->refclk_freq) / NSEC_PER_SEC;
647 am65_cpts_write32(cpts, val, genf[req->index].comp_hi);
649 am65_cpts_write32(cpts, val, genf[req->index].comp_lo);
651 am65_cpts_write32(cpts, val, genf[req->index].length);
653 am65_cpts_write32(cpts, 0, genf[req->index].control);
654 am65_cpts_write32(cpts, 0, genf[req->index].ppm_hi);
655 am65_cpts_write32(cpts, 0, genf[req->index].ppm_low);
657 cpts->genf_enable |= BIT(req->index);
659 am65_cpts_write32(cpts, 0, genf[req->index].length);
661 cpts->genf_enable &= ~BIT(req->index);
665 static int am65_cpts_perout_enable(struct am65_cpts *cpts,
668 if (req->index >= cpts->ptp_info.n_per_out)
671 if (cpts->pps_present && req->index == cpts->pps_genf_idx)
674 if (!!(cpts->genf_enable & BIT(req->index)) == !!on)
677 mutex_lock(&cpts->ptp_clk_lock);
678 am65_cpts_perout_enable_hw(cpts, req, on);
679 mutex_unlock(&cpts->ptp_clk_lock);
681 dev_dbg(cpts->dev, "%s: GenF:%u %s\n",
687 static int am65_cpts_pps_enable(struct am65_cpts *cpts, int on)
694 if (!cpts->pps_present)
697 if (cpts->pps_enabled == !!on)
700 mutex_lock(&cpts->ptp_clk_lock);
703 am65_cpts_extts_enable_hw(cpts, cpts->pps_hw_ts_idx, on);
705 ns = am65_cpts_gettime(cpts, NULL);
711 rq.perout.index = cpts->pps_genf_idx;
713 am65_cpts_perout_enable_hw(cpts, &rq.perout, on);
714 cpts->pps_enabled = true;
716 rq.perout.index = cpts->pps_genf_idx;
717 am65_cpts_perout_enable_hw(cpts, &rq.perout, on);
718 am65_cpts_extts_enable_hw(cpts, cpts->pps_hw_ts_idx, on);
719 cpts->pps_enabled = false;
722 mutex_unlock(&cpts->ptp_clk_lock);
724 dev_dbg(cpts->dev, "%s: pps: %s\n",
732 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
736 return am65_cpts_extts_enable(cpts, rq->extts.index, on);
738 return am65_cpts_perout_enable(cpts, &rq->perout, on);
740 return am65_cpts_pps_enable(cpts, on);
761 static bool am65_cpts_match_tx_ts(struct am65_cpts *cpts,
777 spin_lock_irqsave(&cpts->txq.lock, flags);
778 skb_queue_splice_init(&cpts->txq, &txq_list);
779 spin_unlock_irqrestore(&cpts->txq.lock, flags);
781 /* no need to grab txq.lock as access is always done under cpts->lock */
796 dev_dbg(cpts->dev,
804 dev_dbg(cpts->dev,
812 spin_lock_irqsave(&cpts->txq.lock, flags);
813 skb_queue_splice(&txq_list, &cpts->txq);
814 spin_unlock_irqrestore(&cpts->txq.lock, flags);
819 static void am65_cpts_find_ts(struct am65_cpts *cpts)
827 spin_lock_irqsave(&cpts->lock, flags);
828 list_splice_init(&cpts->events, &events);
829 spin_unlock_irqrestore(&cpts->lock, flags);
833 if (am65_cpts_match_tx_ts(cpts, event) ||
840 spin_lock_irqsave(&cpts->lock, flags);
841 list_splice_tail(&events, &cpts->events);
842 list_splice_tail(&events_free, &cpts->pool);
843 spin_unlock_irqrestore(&cpts->lock, flags);
848 struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
852 am65_cpts_find_ts(cpts);
854 spin_lock_irqsave(&cpts->txq.lock, flags);
855 if (!skb_queue_empty(&cpts->txq))
857 spin_unlock_irqrestore(&cpts->txq.lock, flags);
864 * @cpts: cpts handle
870 void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en)
874 mutex_lock(&cpts->ptp_clk_lock);
875 val = am65_cpts_read32(cpts, control);
880 am65_cpts_write32(cpts, val, control);
881 mutex_unlock(&cpts->ptp_clk_lock);
911 * @cpts: cpts handle
917 void am65_cpts_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb)
930 skb_queue_tail(&cpts->txq, skb);
931 ptp_schedule_worker(cpts->ptp_clock, 0);
937 * @cpts: cpts handle
941 * It checks if packet can be timestamped, fills internal cpts data
944 void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb)
962 int am65_cpts_phc_index(struct am65_cpts *cpts)
964 return cpts->phc_index;
970 struct am65_cpts *cpts = data;
972 of_clk_del_provider(cpts->clk_mux_np);
973 clk_hw_unregister_mux(cpts->clk_mux_hw);
974 of_node_put(cpts->clk_mux_np);
977 static int cpts_of_mux_clk_setup(struct am65_cpts *cpts,
986 cpts->clk_mux_np = of_get_child_by_name(node, "refclk-mux");
987 if (!cpts->clk_mux_np)
990 num_parents = of_clk_get_parent_count(cpts->clk_mux_np);
992 dev_err(cpts->dev, "mux-clock %pOF must have parents\n",
993 cpts->clk_mux_np);
997 parent_names = devm_kcalloc(cpts->dev, sizeof(char *), num_parents,
1004 of_clk_parent_fill(cpts->clk_mux_np, parent_names, num_parents);
1006 clk_mux_name = devm_kasprintf(cpts->dev, GFP_KERNEL, "%s.%pOFn",
1007 dev_name(cpts->dev), cpts->clk_mux_np);
1013 reg = &cpts->reg->rftclk_sel;
1017 cpts->clk_mux_hw = clk_hw_register_mux(NULL, clk_mux_name,
1020 if (IS_ERR(cpts->clk_mux_hw)) {
1021 ret = PTR_ERR(cpts->clk_mux_hw);
1025 ret = of_clk_add_hw_provider(cpts->clk_mux_np, of_clk_hw_simple_get,
1026 cpts->clk_mux_hw);
1030 ret = devm_add_action_or_reset(cpts->dev, cpts_free_clk_mux, cpts);
1032 dev_err(cpts->dev, "failed to add clkmux reset action %d", ret);
1037 clk_hw_unregister_mux(cpts->clk_mux_hw);
1039 of_node_put(cpts->clk_mux_np);
1043 static int am65_cpts_of_parse(struct am65_cpts *cpts, struct device_node *node)
1047 if (!of_property_read_u32(node, "ti,cpts-ext-ts-inputs", &prop[0]))
1048 cpts->ext_ts_inputs = prop[0];
1050 if (!of_property_read_u32(node, "ti,cpts-periodic-outputs", &prop[0]))
1051 cpts->genf_num = prop[0];
1054 cpts->pps_present = true;
1057 dev_err(cpts->dev, "invalid HWx_TS_PUSH index: %u provided\n", prop[0]);
1058 cpts->pps_present = false;
1061 dev_err(cpts->dev, "invalid GENFy index: %u provided\n", prop[1]);
1062 cpts->pps_present = false;
1064 if (cpts->pps_present) {
1065 cpts->pps_hw_ts_idx = prop[0];
1066 cpts->pps_genf_idx = prop[1];
1070 return cpts_of_mux_clk_setup(cpts, node);
1073 void am65_cpts_release(struct am65_cpts *cpts)
1075 ptp_clock_unregister(cpts->ptp_clock);
1076 am65_cpts_disable(cpts);
1077 clk_disable_unprepare(cpts->refclk);
1084 struct am65_cpts *cpts;
1087 cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
1088 if (!cpts)
1091 cpts->dev = dev;
1092 cpts->reg = (struct am65_cpts_regs __iomem *)regs;
1094 cpts->irq = of_irq_get_byname(node, "cpts");
1095 if (cpts->irq <= 0) {
1096 ret = cpts->irq ?: -ENXIO;
1101 ret = am65_cpts_of_parse(cpts, node);
1105 mutex_init(&cpts->ptp_clk_lock);
1106 INIT_LIST_HEAD(&cpts->events);
1107 INIT_LIST_HEAD(&cpts->pool);
1108 spin_lock_init(&cpts->lock);
1109 skb_queue_head_init(&cpts->txq);
1112 list_add(&cpts->pool_data[i].list, &cpts->pool);
1114 cpts->refclk = devm_get_clk_from_child(dev, node, "cpts");
1115 if (IS_ERR(cpts->refclk)) {
1116 ret = PTR_ERR(cpts->refclk);
1121 ret = clk_prepare_enable(cpts->refclk);
1127 cpts->refclk_freq = clk_get_rate(cpts->refclk);
1129 am65_ptp_info.max_adj = cpts->refclk_freq / AM65_CPTS_MIN_PPM;
1130 cpts->ptp_info = am65_ptp_info;
1132 if (cpts->ext_ts_inputs)
1133 cpts->ptp_info.n_ext_ts = cpts->ext_ts_inputs;
1134 if (cpts->genf_num)
1135 cpts->ptp_info.n_per_out = cpts->genf_num;
1136 if (cpts->pps_present)
1137 cpts->ptp_info.pps = 1;
1139 am65_cpts_set_add_val(cpts);
1141 am65_cpts_write32(cpts, AM65_CPTS_CONTROL_EN |
1145 am65_cpts_write32(cpts, AM65_CPTS_INT_ENABLE_TS_PEND_EN, int_enable);
1148 am65_cpts_settime(cpts, ktime_to_ns(ktime_get_real()));
1150 cpts->ptp_clock = ptp_clock_register(&cpts->ptp_info, cpts->dev);
1151 if (IS_ERR_OR_NULL(cpts->ptp_clock)) {
1153 PTR_ERR(cpts->ptp_clock));
1154 ret = cpts->ptp_clock ? PTR_ERR(cpts->ptp_clock) : -ENODEV;
1157 cpts->phc_index = ptp_clock_index(cpts->ptp_clock);
1159 ret = devm_request_threaded_irq(dev, cpts->irq, NULL,
1161 IRQF_ONESHOT, dev_name(dev), cpts);
1163 dev_err(cpts->dev, "error attaching irq %d\n", ret);
1168 am65_cpts_read32(cpts, idver),
1169 cpts->refclk_freq, cpts->ts_add_val, cpts->pps_present);
1171 return cpts;
1174 am65_cpts_release(cpts);
1176 clk_disable_unprepare(cpts->refclk);
1181 void am65_cpts_suspend(struct am65_cpts *cpts)
1184 cpts->sr_control = am65_cpts_read32(cpts, control);
1185 cpts->sr_int_enable = am65_cpts_read32(cpts, int_enable);
1186 cpts->sr_rftclk_sel = am65_cpts_read32(cpts, rftclk_sel);
1187 cpts->sr_ts_ppm_hi = am65_cpts_read32(cpts, ts_ppm_hi);
1188 cpts->sr_ts_ppm_low = am65_cpts_read32(cpts, ts_ppm_low);
1189 cpts->sr_cpts_ns = am65_cpts_gettime(cpts, NULL);
1190 cpts->sr_ktime_ns = ktime_to_ns(ktime_get_real());
1191 am65_cpts_disable(cpts);
1192 clk_disable(cpts->refclk);
1195 memcpy_fromio(&cpts->sr_genf, &cpts->reg->genf, sizeof(cpts->sr_genf));
1198 memcpy_fromio(&cpts->sr_estf, &cpts->reg->estf, sizeof(cpts->sr_estf));
1202 void am65_cpts_resume(struct am65_cpts *cpts)
1208 clk_enable(cpts->refclk);
1209 am65_cpts_write32(cpts, cpts->sr_rftclk_sel, rftclk_sel);
1210 am65_cpts_set_add_val(cpts);
1211 am65_cpts_write32(cpts, cpts->sr_control, control);
1212 am65_cpts_write32(cpts, cpts->sr_int_enable, int_enable);
1216 ktime_ns -= cpts->sr_ktime_ns;
1217 am65_cpts_settime(cpts, cpts->sr_cpts_ns + ktime_ns);
1220 am65_cpts_write32(cpts, cpts->sr_ts_ppm_hi, ts_ppm_hi);
1221 am65_cpts_write32(cpts, cpts->sr_ts_ppm_low, ts_ppm_low);
1225 am65_cpts_write32(cpts, 0, genf[i].length); /* TRM sequence */
1226 am65_cpts_write32(cpts, cpts->sr_genf[i].comp_hi, genf[i].comp_hi);
1227 am65_cpts_write32(cpts, cpts->sr_genf[i].comp_lo, genf[i].comp_lo);
1228 am65_cpts_write32(cpts, cpts->sr_genf[i].length, genf[i].length);
1229 am65_cpts_write32(cpts, cpts->sr_genf[i].control, genf[i].control);
1230 am65_cpts_write32(cpts, cpts->sr_genf[i].ppm_hi, genf[i].ppm_hi);
1231 am65_cpts_write32(cpts, cpts->sr_genf[i].ppm_low, genf[i].ppm_low);
1236 am65_cpts_write32(cpts, 0, estf[i].length); /* TRM sequence */
1237 am65_cpts_write32(cpts, cpts->sr_estf[i].comp_hi, estf[i].comp_hi);
1238 am65_cpts_write32(cpts, cpts->sr_estf[i].comp_lo, estf[i].comp_lo);
1239 am65_cpts_write32(cpts, cpts->sr_estf[i].length, estf[i].length);
1240 am65_cpts_write32(cpts, cpts->sr_estf[i].control, estf[i].control);
1241 am65_cpts_write32(cpts, cpts->sr_estf[i].ppm_hi, estf[i].ppm_hi);
1242 am65_cpts_write32(cpts, cpts->sr_estf[i].ppm_low, estf[i].ppm_low);
1251 struct am65_cpts *cpts;
1254 base = devm_platform_ioremap_resource_byname(pdev, "cpts");
1258 cpts = am65_cpts_create(dev, base, node);
1259 return PTR_ERR_OR_ZERO(cpts);
1263 { .compatible = "ti,am65-cpts", },
1264 { .compatible = "ti,j721e-cpts", },
1272 .name = "am65-cpts",