1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2013-2016 Freescale Semiconductor Inc.
4 * Copyright 2016-2018 NXP
5 * Copyright 2020 NXP
6 */
7
8#include <linux/module.h>
9#include <linux/of.h>
10#include <linux/of_address.h>
11#include <linux/fsl/mc.h>
12
13#include "dpaa2-ptp.h"
14
15static int dpaa2_ptp_enable(struct ptp_clock_info *ptp,
16 struct ptp_clock_request *rq, int on)
17{
18 struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
19 struct fsl_mc_device *mc_dev;
20 struct device *dev;
21 u32 mask = 0;
22 u32 bit;
23 int err;
24
25 dev = ptp_qoriq->dev;
26 mc_dev = to_fsl_mc_device(dev);
27
28 switch (rq->type) {
29 case PTP_CLK_REQ_EXTTS:
30 switch (rq->extts.index) {
31 case 0:
32 bit = DPRTC_EVENT_ETS1;
33 break;
34 case 1:
35 bit = DPRTC_EVENT_ETS2;
36 break;
37 default:
38 return -EINVAL;
39 }
40 if (on)
41 extts_clean_up(ptp_qoriq, index: rq->extts.index, update_event: false);
42 break;
43 case PTP_CLK_REQ_PPS:
44 bit = DPRTC_EVENT_PPS;
45 break;
46 default:
47 return -EOPNOTSUPP;
48 }
49
50 err = dprtc_get_irq_mask(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle,
51 DPRTC_IRQ_INDEX, mask: &mask);
52 if (err < 0) {
53 dev_err(dev, "dprtc_get_irq_mask(): %d\n", err);
54 return err;
55 }
56
57 if (on)
58 mask |= bit;
59 else
60 mask &= ~bit;
61
62 err = dprtc_set_irq_mask(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle,
63 DPRTC_IRQ_INDEX, mask);
64 if (err < 0) {
65 dev_err(dev, "dprtc_set_irq_mask(): %d\n", err);
66 return err;
67 }
68
69 return 0;
70}
71
72static const struct ptp_clock_info dpaa2_ptp_caps = {
73 .owner = THIS_MODULE,
74 .name = "DPAA2 PTP Clock",
75 .max_adj = 512000,
76 .n_alarm = 2,
77 .n_ext_ts = 2,
78 .n_per_out = 3,
79 .n_pins = 0,
80 .pps = 1,
81 .adjfine = ptp_qoriq_adjfine,
82 .adjtime = ptp_qoriq_adjtime,
83 .gettime64 = ptp_qoriq_gettime,
84 .settime64 = ptp_qoriq_settime,
85 .enable = dpaa2_ptp_enable,
86};
87
88static irqreturn_t dpaa2_ptp_irq_handler_thread(int irq, void *priv)
89{
90 struct ptp_qoriq *ptp_qoriq = priv;
91 struct ptp_clock_event event;
92 struct fsl_mc_device *mc_dev;
93 struct device *dev;
94 u32 status = 0;
95 int err;
96
97 dev = ptp_qoriq->dev;
98 mc_dev = to_fsl_mc_device(dev);
99
100 err = dprtc_get_irq_status(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle,
101 DPRTC_IRQ_INDEX, status: &status);
102 if (unlikely(err)) {
103 dev_err(dev, "dprtc_get_irq_status err %d\n", err);
104 return IRQ_NONE;
105 }
106
107 if (status & DPRTC_EVENT_PPS) {
108 event.type = PTP_CLOCK_PPS;
109 ptp_clock_event(ptp: ptp_qoriq->clock, event: &event);
110 }
111
112 if (status & DPRTC_EVENT_ETS1)
113 extts_clean_up(ptp_qoriq, index: 0, update_event: true);
114
115 if (status & DPRTC_EVENT_ETS2)
116 extts_clean_up(ptp_qoriq, index: 1, update_event: true);
117
118 err = dprtc_clear_irq_status(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle,
119 DPRTC_IRQ_INDEX, status);
120 if (unlikely(err)) {
121 dev_err(dev, "dprtc_clear_irq_status err %d\n", err);
122 return IRQ_NONE;
123 }
124
125 return IRQ_HANDLED;
126}
127
128static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
129{
130 struct device *dev = &mc_dev->dev;
131 struct ptp_qoriq *ptp_qoriq;
132 struct device_node *node;
133 void __iomem *base;
134 int err;
135
136 ptp_qoriq = devm_kzalloc(dev, size: sizeof(*ptp_qoriq), GFP_KERNEL);
137 if (!ptp_qoriq)
138 return -ENOMEM;
139
140 err = fsl_mc_portal_allocate(mc_dev, mc_io_flags: 0, new_mc_io: &mc_dev->mc_io);
141 if (err) {
142 if (err == -ENXIO)
143 err = -EPROBE_DEFER;
144 else
145 dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
146 goto err_exit;
147 }
148
149 err = dprtc_open(mc_io: mc_dev->mc_io, cmd_flags: 0, dprtc_id: mc_dev->obj_desc.id,
150 token: &mc_dev->mc_handle);
151 if (err) {
152 dev_err(dev, "dprtc_open err %d\n", err);
153 goto err_free_mcp;
154 }
155
156 ptp_qoriq->dev = dev;
157
158 node = of_find_compatible_node(NULL, NULL, compat: "fsl,dpaa2-ptp");
159 if (!node) {
160 err = -ENODEV;
161 goto err_close;
162 }
163
164 dev->of_node = node;
165
166 base = of_iomap(node, index: 0);
167 if (!base) {
168 err = -ENOMEM;
169 goto err_put;
170 }
171
172 err = fsl_mc_allocate_irqs(mc_dev);
173 if (err) {
174 dev_err(dev, "MC irqs allocation failed\n");
175 goto err_unmap;
176 }
177
178 ptp_qoriq->irq = mc_dev->irqs[0]->virq;
179
180 err = request_threaded_irq(irq: ptp_qoriq->irq, NULL,
181 thread_fn: dpaa2_ptp_irq_handler_thread,
182 IRQF_NO_SUSPEND | IRQF_ONESHOT,
183 name: dev_name(dev), dev: ptp_qoriq);
184 if (err < 0) {
185 dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
186 goto err_free_mc_irq;
187 }
188
189 err = dprtc_set_irq_enable(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle,
190 DPRTC_IRQ_INDEX, en: 1);
191 if (err < 0) {
192 dev_err(dev, "dprtc_set_irq_enable(): %d\n", err);
193 goto err_free_threaded_irq;
194 }
195
196 err = ptp_qoriq_init(ptp_qoriq, base, caps: &dpaa2_ptp_caps);
197 if (err)
198 goto err_free_threaded_irq;
199
200 dpaa2_phc_index = ptp_qoriq->phc_index;
201 dpaa2_ptp = ptp_qoriq;
202 dev_set_drvdata(dev, data: ptp_qoriq);
203
204 return 0;
205
206err_free_threaded_irq:
207 free_irq(ptp_qoriq->irq, ptp_qoriq);
208err_free_mc_irq:
209 fsl_mc_free_irqs(mc_dev);
210err_unmap:
211 iounmap(addr: base);
212err_put:
213 of_node_put(node);
214err_close:
215 dprtc_close(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle);
216err_free_mcp:
217 fsl_mc_portal_free(mc_io: mc_dev->mc_io);
218err_exit:
219 return err;
220}
221
222static void dpaa2_ptp_remove(struct fsl_mc_device *mc_dev)
223{
224 struct device *dev = &mc_dev->dev;
225 struct ptp_qoriq *ptp_qoriq;
226
227 ptp_qoriq = dev_get_drvdata(dev);
228
229 dpaa2_phc_index = -1;
230 ptp_qoriq_free(ptp_qoriq);
231
232 fsl_mc_free_irqs(mc_dev);
233 dprtc_close(mc_io: mc_dev->mc_io, cmd_flags: 0, token: mc_dev->mc_handle);
234 fsl_mc_portal_free(mc_io: mc_dev->mc_io);
235}
236
237static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = {
238 {
239 .vendor = FSL_MC_VENDOR_FREESCALE,
240 .obj_type = "dprtc",
241 },
242 {}
243};
244MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table);
245
246static struct fsl_mc_driver dpaa2_ptp_drv = {
247 .driver = {
248 .name = KBUILD_MODNAME,
249 .owner = THIS_MODULE,
250 },
251 .probe = dpaa2_ptp_probe,
252 .remove = dpaa2_ptp_remove,
253 .match_id_table = dpaa2_ptp_match_id_table,
254};
255
256module_fsl_mc_driver(dpaa2_ptp_drv);
257
258MODULE_LICENSE("GPL v2");
259MODULE_DESCRIPTION("DPAA2 PTP Clock Driver");
260

source code of linux/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c