diff options
author | Nithin Sujir <nsujir@broadcom.com> | 2013-07-29 16:58:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-30 02:38:52 -0400 |
commit | 92e6457d4cf68ef69bc4f98330c93e198df06a43 (patch) | |
tree | a60ad7edf04f1881225b8e4eb04fd3f394221c24 /drivers/net/ethernet/broadcom/tg3.c | |
parent | 4c305fa2cbe2a85c34899763fcefb843c87b591d (diff) |
tg3: Enable support for timesync gpio output
The PTP_CAPABLE tg3 devices have a gpio output that is toggled when the
free running counter matches a watchdog value. This patch adds support
to set the watchdog and enable this feature.
Since the output is controlled via bits in the EAV_REF_CLCK_CTL
register, we have to read-modify-write it when we stop/resume.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 935170757786..f077c8f5baa1 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -6093,10 +6093,12 @@ static u64 tg3_refclk_read(struct tg3 *tp) | |||
6093 | /* tp->lock must be held */ | 6093 | /* tp->lock must be held */ |
6094 | static void tg3_refclk_write(struct tg3 *tp, u64 newval) | 6094 | static void tg3_refclk_write(struct tg3 *tp, u64 newval) |
6095 | { | 6095 | { |
6096 | tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP); | 6096 | u32 clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL); |
6097 | |||
6098 | tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_STOP); | ||
6097 | tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff); | 6099 | tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff); |
6098 | tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32); | 6100 | tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32); |
6099 | tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME); | 6101 | tw32_f(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_RESUME); |
6100 | } | 6102 | } |
6101 | 6103 | ||
6102 | static inline void tg3_full_lock(struct tg3 *tp, int irq_sync); | 6104 | static inline void tg3_full_lock(struct tg3 *tp, int irq_sync); |
@@ -6212,6 +6214,59 @@ static int tg3_ptp_settime(struct ptp_clock_info *ptp, | |||
6212 | static int tg3_ptp_enable(struct ptp_clock_info *ptp, | 6214 | static int tg3_ptp_enable(struct ptp_clock_info *ptp, |
6213 | struct ptp_clock_request *rq, int on) | 6215 | struct ptp_clock_request *rq, int on) |
6214 | { | 6216 | { |
6217 | struct tg3 *tp = container_of(ptp, struct tg3, ptp_info); | ||
6218 | u32 clock_ctl; | ||
6219 | int rval = 0; | ||
6220 | |||
6221 | switch (rq->type) { | ||
6222 | case PTP_CLK_REQ_PEROUT: | ||
6223 | if (rq->perout.index != 0) | ||
6224 | return -EINVAL; | ||
6225 | |||
6226 | tg3_full_lock(tp, 0); | ||
6227 | clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL); | ||
6228 | clock_ctl &= ~TG3_EAV_CTL_TSYNC_GPIO_MASK; | ||
6229 | |||
6230 | if (on) { | ||
6231 | u64 nsec; | ||
6232 | |||
6233 | nsec = rq->perout.start.sec * 1000000000ULL + | ||
6234 | rq->perout.start.nsec; | ||
6235 | |||
6236 | if (rq->perout.period.sec || rq->perout.period.nsec) { | ||
6237 | netdev_warn(tp->dev, | ||
6238 | "Device supports only a one-shot timesync output, period must be 0\n"); | ||
6239 | rval = -EINVAL; | ||
6240 | goto err_out; | ||
6241 | } | ||
6242 | |||
6243 | if (nsec & (1ULL << 63)) { | ||
6244 | netdev_warn(tp->dev, | ||
6245 | "Start value (nsec) is over limit. Maximum size of start is only 63 bits\n"); | ||
6246 | rval = -EINVAL; | ||
6247 | goto err_out; | ||
6248 | } | ||
6249 | |||
6250 | tw32(TG3_EAV_WATCHDOG0_LSB, (nsec & 0xffffffff)); | ||
6251 | tw32(TG3_EAV_WATCHDOG0_MSB, | ||
6252 | TG3_EAV_WATCHDOG0_EN | | ||
6253 | ((nsec >> 32) & TG3_EAV_WATCHDOG_MSB_MASK)); | ||
6254 | |||
6255 | tw32(TG3_EAV_REF_CLCK_CTL, | ||
6256 | clock_ctl | TG3_EAV_CTL_TSYNC_WDOG0); | ||
6257 | } else { | ||
6258 | tw32(TG3_EAV_WATCHDOG0_MSB, 0); | ||
6259 | tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl); | ||
6260 | } | ||
6261 | |||
6262 | err_out: | ||
6263 | tg3_full_unlock(tp); | ||
6264 | return rval; | ||
6265 | |||
6266 | default: | ||
6267 | break; | ||
6268 | } | ||
6269 | |||
6215 | return -EOPNOTSUPP; | 6270 | return -EOPNOTSUPP; |
6216 | } | 6271 | } |
6217 | 6272 | ||
@@ -6221,7 +6276,7 @@ static const struct ptp_clock_info tg3_ptp_caps = { | |||
6221 | .max_adj = 250000000, | 6276 | .max_adj = 250000000, |
6222 | .n_alarm = 0, | 6277 | .n_alarm = 0, |
6223 | .n_ext_ts = 0, | 6278 | .n_ext_ts = 0, |
6224 | .n_per_out = 0, | 6279 | .n_per_out = 1, |
6225 | .pps = 0, | 6280 | .pps = 0, |
6226 | .adjfreq = tg3_ptp_adjfreq, | 6281 | .adjfreq = tg3_ptp_adjfreq, |
6227 | .adjtime = tg3_ptp_adjtime, | 6282 | .adjtime = tg3_ptp_adjtime, |