ctu_can_fd_hw.c 19.2 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2
/*******************************************************************************
Martin Jeřábek's avatar
Martin Jeřábek committed
3
 *
4
 * CTU CAN FD IP Core
5
 * Copyright (C) 2015-2018
Martin Jeřábek's avatar
Martin Jeřábek committed
6
 *
7 8
 * Authors:
 *     Ondrej Ille <ondrej.ille@gmail.com>
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
9
 *     Martin Jerabek <martin.jerabek01@gmail.com>
Martin Jeřábek's avatar
Martin Jeřábek committed
10 11
 *
 * Project advisors:
12 13
 *	Jiri Novak <jnovak@fel.cvut.cz>
 *	Pavel Pisa <pisa@cmp.felk.cvut.cz>
Martin Jeřábek's avatar
Martin Jeřábek committed
14
 *
15 16 17
 * Department of Measurement         (http://meas.fel.cvut.cz/)
 * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
 * Czech Technical University        (http://www.cvut.cz/)
Martin Jeřábek's avatar
Martin Jeřábek committed
18
 *
19 20 21 22
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
Martin Jeřábek's avatar
Martin Jeřábek committed
23
 *
24 25 26 27
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
Martin Jeřábek's avatar
Martin Jeřábek committed
28
 *
29 30
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
31 32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
Martin Jeřábek's avatar
Martin Jeřábek committed
33
 *
34
 ******************************************************************************/
35

36 37
#ifndef __KERNEL__
# include "ctu_can_fd_linux_defs.h"
Martin Jeřábek's avatar
Martin Jeřábek committed
38 39
#else
# include <linux/can/dev.h>
40 41
#endif

42
#include "ctu_can_fd_frame.h"
43
//#include "ctu_can_fd_regs.h"
44
#include "ctu_can_fd_hw.h"
45

46 47
void ctu_can_fd_write32(struct ctucanfd_priv *priv,
			enum ctu_can_fd_can_registers reg, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
48 49 50 51
{
	iowrite32(val, (char *)priv->mem_base + reg);
}

52 53
void ctu_can_fd_write32_be(struct ctucanfd_priv *priv,
			   enum ctu_can_fd_can_registers reg, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
54 55 56 57
{
	iowrite32(val, (char *)priv->mem_base + reg);
}

58 59
u32 ctu_can_fd_read32(struct ctucanfd_priv *priv,
		      enum ctu_can_fd_can_registers reg)
Martin Jeřábek's avatar
Martin Jeřábek committed
60
{
61
	return ioread32((char *)priv->mem_base + reg);
Martin Jeřábek's avatar
Martin Jeřábek committed
62 63
}

64 65
u32 ctu_can_fd_read32_be(struct ctucanfd_priv *priv,
			 enum ctu_can_fd_can_registers reg)
Martin Jeřábek's avatar
Martin Jeřábek committed
66
{
67
	return ioread32be((char *)priv->mem_base + reg);
Martin Jeřábek's avatar
Martin Jeřábek committed
68 69 70
}

static void ctu_can_fd_write_txt_buf(struct ctucanfd_priv *priv,
71 72
				     enum ctu_can_fd_can_registers buf_base,
				     u32 offset, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
73 74 75 76
{
	priv->write_reg(priv, buf_base + offset, val);
}

Martin Jeřábek's avatar
Martin Jeřábek committed
77
static inline union ctu_can_fd_identifier_w ctu_can_fd_id_to_hwid(canid_t id)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
78
{
Martin Jeřábek's avatar
Martin Jeřábek committed
79
	union ctu_can_fd_identifier_w hwid;
80

Martin Jeřábek's avatar
Martin Jeřábek committed
81
	hwid.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
82

83
	if (id & CAN_EFF_FLAG) {
Martin Jeřábek's avatar
Martin Jeřábek committed
84
		hwid.s.identifier_base = (id & CAN_EFF_MASK) >> 18;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
85

86
		/* getting lowest 18 bits, replace with sth nicer... */
Martin Jeřábek's avatar
Martin Jeřábek committed
87
		hwid.s.identifier_ext = (id & 0x3FFFF);
88
	} else {
Martin Jeřábek's avatar
Martin Jeřábek committed
89
		hwid.s.identifier_base = id & CAN_SFF_MASK;
90
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
91
	return hwid;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
92
}
Martin Jeřábek's avatar
Martin Jeřábek committed
93 94

// TODO: rename or do not depend on previous value of id
95
static inline void ctu_can_fd_hwid_to_id(union ctu_can_fd_identifier_w hwid,
96
					 canid_t *id,
Martin Jeřábek's avatar
Martin Jeřábek committed
97
					 enum ctu_can_fd_frame_form_w_ide type)
Martin Jeřábek's avatar
Martin Jeřábek committed
98
{
99
	/* Preserve flags which we dont set */
100
	*id &= ~(CAN_EFF_FLAG | CAN_EFF_MASK);
Martin Jeřábek's avatar
Martin Jeřábek committed
101

102
	if (type == EXTENDED) {
103 104 105
		*id |= CAN_EFF_FLAG;
		*id |= hwid.s.identifier_base << 18;
		*id |= hwid.s.identifier_ext;
106
	} else {
107
		*id = hwid.s.identifier_base;
108
	}
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
109 110
}

111 112
static bool ctu_can_fd_len_to_dlc(u8 len, u8 *dlc)
{
113 114
	*dlc = can_len2dlc(len);
	return true;
115 116
}

117
bool ctu_can_fd_check_access(struct ctucanfd_priv *priv)
118 119
{
	union ctu_can_fd_device_id_version reg;
120

Martin Jeřábek's avatar
Martin Jeřábek committed
121
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
Martin Jeřábek's avatar
Martin Jeřábek committed
122

123 124
	if (reg.s.device_id != CTU_CAN_FD_ID)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
125

126
	return true;
127 128
}

129
u32 ctu_can_fd_get_version(struct ctucanfd_priv *priv)
130 131
{
	union ctu_can_fd_device_id_version reg;
132

Martin Jeřábek's avatar
Martin Jeřábek committed
133
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
134
	return reg.s.ver_major * 10 + reg.s.ver_minor;
135 136
}

137
void ctu_can_fd_enable(struct ctucanfd_priv *priv, bool enable)
138
{
139
	union ctu_can_fd_mode_settings reg;
140

Martin Jeřábek's avatar
Martin Jeřábek committed
141
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
142
	reg.s.ena = enable ? CTU_CAN_ENABLED : CTU_CAN_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
143 144 145 146 147
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
}

void ctu_can_fd_reset(struct ctucanfd_priv *priv)
{
148
	union ctu_can_fd_mode_settings mode;
149

150
	mode.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
151
	mode.s.rst = 1;
152 153 154
	/* it does not matter that we overwrite the rest of the reg
	 * - we're resetting
	 */
Martin Jeřábek's avatar
Martin Jeřábek committed
155
	priv->write_reg(priv, CTU_CAN_FD_MODE, mode.u32);
156 157
}

158
bool ctu_can_fd_set_ret_limit(struct ctucanfd_priv *priv, bool enable, u8 limit)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
159
{
160
	union ctu_can_fd_mode_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
161

162 163
	if (limit > CTU_CAN_FD_RETR_MAX)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
164

Martin Jeřábek's avatar
Martin Jeřábek committed
165
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
166
	reg.s.rtrle = enable ? RTRLE_ENABLED : RTRLE_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
167
	reg.s.rtrth = limit & 0xF;
Martin Jeřábek's avatar
Martin Jeřábek committed
168
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
169
	return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
170 171
}

172 173
void ctu_can_fd_set_mode_reg(struct ctucanfd_priv *priv,
			     const struct can_ctrlmode *mode)
174
{
Martin Jeřábek's avatar
Martin Jeřábek committed
175
	u32 flags = mode->flags;
176
	union ctu_can_fd_mode_settings reg;
177

Martin Jeřábek's avatar
Martin Jeřábek committed
178
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
Martin Jeřábek's avatar
Martin Jeřábek committed
179

180
	if (mode->mask & CAN_CTRLMODE_LOOPBACK)
Martin Jeřábek's avatar
Martin Jeřábek committed
181
		reg.s.ilbp = flags & CAN_CTRLMODE_LOOPBACK ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
182
					INT_LOOP_ENABLED : INT_LOOP_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
183

184
	if (mode->mask & CAN_CTRLMODE_LISTENONLY)
Martin Jeřábek's avatar
Martin Jeřábek committed
185
		reg.s.lom = flags & CAN_CTRLMODE_LISTENONLY ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
186
					LOM_ENABLED : LOM_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
187

188
	if (mode->mask & CAN_CTRLMODE_3_SAMPLES)
Martin Jeřábek's avatar
Martin Jeřábek committed
189
		reg.s.tsm = flags & CAN_CTRLMODE_3_SAMPLES ?
190
				TSM_ENABLE : TSM_DISABLE;
Martin Jeřábek's avatar
Martin Jeřábek committed
191

192
	if (mode->mask & CAN_CTRLMODE_FD)
Martin Jeřábek's avatar
Martin Jeřábek committed
193
		reg.s.fde = flags & CAN_CTRLMODE_FD ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
194
				FDE_ENABLE : FDE_DISABLE;
Martin Jeřábek's avatar
Martin Jeřábek committed
195

196
	if (mode->mask & CAN_CTRLMODE_PRESUME_ACK)
Martin Jeřábek's avatar
Martin Jeřábek committed
197
		reg.s.stm = flags & CAN_CTRLMODE_PRESUME_ACK ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
198
				STM_ENABLED : STM_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
199

200
	if (mode->mask & CAN_CTRLMODE_FD_NON_ISO)
Martin Jeřábek's avatar
Martin Jeřábek committed
201
		reg.s.nisofd = flags & CAN_CTRLMODE_FD_NON_ISO ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
202
				NON_ISO_FD : ISO_FD;
203

Martin Jeřábek's avatar
Martin Jeřábek committed
204
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
205 206
}

Martin Jeřábek's avatar
Martin Jeřábek committed
207 208
/* TODO: use atomic 16bit accesses instead of read-modify-write */

209
void ctu_can_fd_rel_rx_buf(struct ctucanfd_priv *priv)
210
{
211
	union ctu_can_fd_command reg;
212

213
	reg.u32 = 0;
214
	reg.s.rrb = 1;
215
	priv->write_reg(priv, CTU_CAN_FD_COMMAND, reg.u32);
216 217
}

218
void ctu_can_fd_clr_overrun_flag(struct ctucanfd_priv *priv)
219
{
220
	union ctu_can_fd_command reg;
221

222
	reg.u32 = 0;
223
	reg.s.cdo = 1;
224
	priv->write_reg(priv, CTU_CAN_FD_COMMAND, reg.u32);
225 226
}

227
void ctu_can_fd_abort_tx(struct ctucanfd_priv *priv)
228
{
229
	union ctu_can_fd_command reg;
230

231
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
232
	reg.s.abt = 1;
233
	priv->write_reg(priv, CTU_CAN_FD_COMMAND, reg.u32);
234 235
}

236 237 238 239 240
// TODO: rather than set(value, mask) interface, provide
//       native set(val), clr(val) interface to potentially
//       avoid unnecessary write
static void ctu_can_fd_int_conf(struct ctucanfd_priv *priv,
				enum ctu_can_fd_can_registers sreg,
241
				enum ctu_can_fd_can_registers creg,
242 243
				union ctu_can_fd_int_stat mask,
				union ctu_can_fd_int_stat val)
244
{
Martin Jeřábek's avatar
Martin Jeřábek committed
245 246
	priv->write_reg(priv, sreg, mask.u32 & val.u32);
	priv->write_reg(priv, creg, mask.u32 & (~val.u32));
247 248
}

249 250
void ctu_can_fd_int_ena(struct ctucanfd_priv *priv,
			union ctu_can_fd_int_stat mask,
251
			union ctu_can_fd_int_stat val)
252
{
253 254
	ctu_can_fd_int_conf(priv, CTU_CAN_FD_INT_ENA_SET,
			    CTU_CAN_FD_INT_ENA_CLR, mask, val);
255 256
}

257 258
void ctu_can_fd_int_mask(struct ctucanfd_priv *priv,
			 union ctu_can_fd_int_stat mask,
259
			 union ctu_can_fd_int_stat val)
260
{
261 262
	ctu_can_fd_int_conf(priv, CTU_CAN_FD_INT_MASK_SET,
			    CTU_CAN_FD_INT_MASK_CLR, mask, val);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
263 264
}

265 266
void ctu_can_fd_set_mode(struct ctucanfd_priv *priv,
			 const struct can_ctrlmode *mode)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
267
{
268
	ctu_can_fd_set_mode_reg(priv, mode);
Martin Jeřábek's avatar
Martin Jeřábek committed
269

270
	/* One shot mode supported indirectly via Retransmitt limit */
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
271
	if (mode->mask & CAN_CTRLMODE_ONE_SHOT)
272 273
		ctu_can_fd_set_ret_limit(priv, !!(mode->flags &
					 CAN_CTRLMODE_ONE_SHOT), 0);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
274

275
	/* Bus error reporting -> Allow Error interrupt */
Martin Jeřábek's avatar
Martin Jeřábek committed
276 277
	if (mode->mask & CAN_CTRLMODE_BERR_REPORTING) {
		union ctu_can_fd_int_stat ena, mask;
278

279 280
		ena.u32 = 0;
		mask.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
281 282 283 284
		ena.s.bei = !!(mode->flags & CAN_CTRLMODE_ONE_SHOT);
		mask.s.bei = 1;
		ctu_can_fd_int_ena(priv, ena, mask);
	}
285 286
}

287
const struct can_bittiming_const ctu_can_fd_bit_timing_max = {
288
	.name = "ctu_can_fd",
289 290 291 292 293 294 295 296 297 298
	.tseg1_min = 2,
	.tseg1_max = 190,
	.tseg2_min = 1,
	.tseg2_max = 63,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

299
const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = {
300
	.name = "ctu_can_fd",
301 302 303 304 305 306 307 308 309 310
	.tseg1_min = 2,
	.tseg1_max = 94,
	.tseg2_min = 1,
	.tseg2_max = 31,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

311
void ctu_can_fd_set_nom_bittiming(struct ctucanfd_priv *priv,
312
				  struct can_bittiming *nbt)
313 314
{
	union ctu_can_fd_btr btr;
315

316
	/* The timing calculation functions have only constraints on tseg1,
317
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
318 319
	 * and stored into prog_seg and phase_seg1. In CTU CAN FD, PROP is
	 * 7 bits wide but PH1 only 6, so we must re-distribute the values here.
320 321 322
	 */
	u32 prop_seg = nbt->prop_seg;
	u32 phase_seg1 = nbt->phase_seg1;
323

324 325 326 327 328 329 330 331
	if (phase_seg1 > 63) {
		prop_seg += phase_seg1 - 63;
		phase_seg1 = 63;
		nbt->prop_seg = prop_seg;
		nbt->phase_seg1 = phase_seg1;
	}

	btr.u32 = 0;
332 333
	btr.s.prop = prop_seg;
	btr.s.ph1 = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
334 335 336
	btr.s.ph2 = nbt->phase_seg2;
	btr.s.brp = nbt->brp;
	btr.s.sjw = nbt->sjw;
337

Martin Jeřábek's avatar
Martin Jeřábek committed
338
	priv->write_reg(priv, CTU_CAN_FD_BTR, btr.u32);
339 340
}

341
void ctu_can_fd_set_data_bittiming(struct ctucanfd_priv *priv,
342
				   struct can_bittiming *dbt)
343 344
{
	union ctu_can_fd_btr_fd btr_fd;
345

346
	/* The timing calculation functions have only constraints on tseg1,
347
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
348 349 350
	 * and stored into prog_seg and phase_seg1. In CTU CAN FD, PROP_FD is
	 * 6 bits wide but PH1_FD only 5, so we must re-distribute the values
	 * here.
351 352 353
	 */
	u32 prop_seg = dbt->prop_seg;
	u32 phase_seg1 = dbt->phase_seg1;
354

355 356 357 358 359 360
	if (phase_seg1 > 31) {
		prop_seg += phase_seg1 - 31;
		phase_seg1 = 31;
		dbt->prop_seg = prop_seg;
		dbt->phase_seg1 = phase_seg1;
	}
361

362
	btr_fd.u32 = 0;
363 364
	btr_fd.s.prop_fd = prop_seg;
	btr_fd.s.ph1_fd = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
365 366 367
	btr_fd.s.ph2_fd = dbt->phase_seg2;
	btr_fd.s.brp_fd = dbt->brp;
	btr_fd.s.sjw_fd = dbt->sjw;
Martin Jeřábek's avatar
Martin Jeřábek committed
368

Martin Jeřábek's avatar
Martin Jeřábek committed
369
	priv->write_reg(priv, CTU_CAN_FD_BTR_FD, btr_fd.u32);
370 371
}

372
void ctu_can_fd_set_err_limits(struct ctucanfd_priv *priv, u8 ewl, u8 erp)
373 374
{
	union ctu_can_fd_ewl_erp_fault_state reg;
375

376
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
377
	reg.s.ew_limit = ewl;
378
	reg.s.erp_limit = erp;
379
	// era, bof, erp are read-only
Martin Jeřábek's avatar
Martin Jeřábek committed
380

Martin Jeřábek's avatar
Martin Jeřábek committed
381
	priv->write_reg(priv, CTU_CAN_FD_EWL, reg.u32);
382 383
}

384 385
void ctu_can_fd_read_err_ctrs(struct ctucanfd_priv *priv,
			      struct can_berr_counter *ctr)
386 387
{
	union ctu_can_fd_rxc_txc reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
388

Martin Jeřábek's avatar
Martin Jeřábek committed
389
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_RXC);
390 391
	ctr->txerr = reg.s.rxc_val;
	ctr->rxerr = reg.s.txc_val;
392 393
}

394
enum can_state ctu_can_fd_read_error_state(struct ctucanfd_priv *priv)
395 396
{
	union ctu_can_fd_ewl_erp_fault_state reg;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
397 398
	union ctu_can_fd_rxc_txc err;

Martin Jeřábek's avatar
Martin Jeřábek committed
399 400
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_EWL);
	err.u32 = priv->read_reg(priv, CTU_CAN_FD_RXC);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
401

402 403 404
	if (reg.s.era) {
		if (reg.s.ew_limit > err.s.rxc_val &&
		    reg.s.ew_limit > err.s.txc_val)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
405 406 407
			return CAN_STATE_ERROR_ACTIVE;
		else
			return CAN_STATE_ERROR_WARNING;
408
	} else if (reg.s.erp) {
409
		return CAN_STATE_ERROR_PASSIVE;
410
	} else if (reg.s.bof) {
411
		return CAN_STATE_BUS_OFF;
412
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
413 414
	WARN(true, "Invalid error state");
	return CAN_STATE_ERROR_PASSIVE;
415 416
}

417 418
void ctu_can_fd_set_err_ctrs(struct ctucanfd_priv *priv,
			     const struct can_berr_counter *ctr)
419 420
{
	union ctu_can_fd_ctr_pres reg;
421

422
	reg.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
423

424 425
	reg.s.ctpv = ctr->txerr;
	reg.s.ptx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
426
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
427

428 429 430
	reg.s.ctpv = ctr->rxerr;
	reg.s.ptx = 0;
	reg.s.prx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
431
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
432 433
}

434
bool ctu_can_fd_get_mask_filter_support(struct ctucanfd_priv *priv, u8 fnum)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
435 436
{
	union ctu_can_fd_filter_control_filter_status reg;
437

Martin Jeřábek's avatar
Martin Jeřábek committed
438
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
439

440 441 442 443
	switch (fnum) {
	case CTU_CAN_FD_FILTER_A:
		if (reg.s.sfa)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
444
	break;
445 446 447
	case CTU_CAN_FD_FILTER_B:
		if (reg.s.sfb)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
448
	break;
449 450 451
	case CTU_CAN_FD_FILTER_C:
		if (reg.s.sfc)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
452 453 454 455 456 457
	break;
	}

	return false;
}

458
bool ctu_can_fd_get_range_filter_support(struct ctucanfd_priv *priv)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
459 460
{
	union ctu_can_fd_filter_control_filter_status reg;
461

Martin Jeřábek's avatar
Martin Jeřábek committed
462
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
463

464
	if (reg.s.sfr)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
465 466 467 468 469
		return true;

	return false;
}

470 471
bool ctu_can_fd_set_mask_filter(struct ctucanfd_priv *priv, u8 fnum,
				bool enable, const struct can_filter *filter)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
472 473
{
	union ctu_can_fd_filter_control_filter_status creg;
474
	enum ctu_can_fd_can_registers maddr, vaddr;
Martin Jeřábek's avatar
Martin Jeřábek committed
475 476
	union ctu_can_fd_identifier_w hwid_mask;
	union ctu_can_fd_identifier_w hwid_val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
477 478
	uint8_t val = 0;

479
	if (!ctu_can_fd_get_mask_filter_support(priv, fnum))
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
480 481 482 483 484
		return false;

	if (enable)
		val = 1;

Martin Jeřábek's avatar
Martin Jeřábek committed
485
	creg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
486

487 488
	switch (fnum) {
	case CTU_CAN_FD_FILTER_A:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
489
		maddr = CTU_CAN_FD_FILTER_A_MASK;
Martin Jeřábek's avatar
Martin Jeřábek committed
490
		vaddr = CTU_CAN_FD_FILTER_A_VAL;
491 492 493
		creg.s.fanb = val;
		creg.s.fane = val;
		creg.s.fafb = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
494
		creg.s.fafe = val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
495
	break;
496
	case CTU_CAN_FD_FILTER_B:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
497 498
		maddr = CTU_CAN_FD_FILTER_B_MASK;
		vaddr = CTU_CAN_FD_FILTER_B_VAL;
499 500 501 502
		creg.s.fbnb = val;
		creg.s.fbne = val;
		creg.s.fbfb = val;
		creg.s.fbfe = val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
503
	break;
504
	case CTU_CAN_FD_FILTER_C:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
505 506
		maddr = CTU_CAN_FD_FILTER_C_MASK;
		vaddr = CTU_CAN_FD_FILTER_C_VAL;
507 508 509 510
		creg.s.fcnb = val;
		creg.s.fcne = val;
		creg.s.fcfb = val;
		creg.s.fcfe = val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
511 512 513 514 515
	break;
	default:
		return false;
	}

Martin Jeřábek's avatar
Martin Jeřábek committed
516 517
	hwid_mask = ctu_can_fd_id_to_hwid(filter->can_id);
	hwid_val = ctu_can_fd_id_to_hwid(filter->can_mask);
Martin Jeřábek's avatar
Martin Jeřábek committed
518 519 520
	priv->write_reg(priv, CTU_CAN_FD_FILTER_CONTROL, creg.u32);
	priv->write_reg(priv, maddr, hwid_mask.u32);
	priv->write_reg(priv, vaddr, hwid_val.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
521 522 523
	return true;
}

524
void ctu_can_fd_set_range_filter(struct ctucanfd_priv *priv, canid_t low_th,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
525 526
				 canid_t high_th, bool enable)
{
Martin Jeřábek's avatar
Martin Jeřábek committed
527
	union ctu_can_fd_identifier_w hwid_low;
528 529
	union ctu_can_fd_identifier_w hwid_high;
	union ctu_can_fd_filter_control_filter_status creg;
Martin Jeřábek's avatar
Martin Jeřábek committed
530

Martin Jeřábek's avatar
Martin Jeřábek committed
531 532
	hwid_low = ctu_can_fd_id_to_hwid(low_th);
	hwid_high = ctu_can_fd_id_to_hwid(high_th);
533

Martin Jeřábek's avatar
Martin Jeřábek committed
534
	creg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Martin Jeřábek's avatar
Martin Jeřábek committed
535

536 537 538 539 540
	creg.s.frnb = enable;
	creg.s.frne = enable;
	creg.s.frfb = enable;
	creg.s.frfe = enable;

Martin Jeřábek's avatar
Martin Jeřábek committed
541 542 543
	priv->write_reg(priv, CTU_CAN_FD_FILTER_CONTROL, creg.u32);
	priv->write_reg(priv, CTU_CAN_FD_FILTER_RAN_LOW, hwid_low.u32);
	priv->write_reg(priv, CTU_CAN_FD_FILTER_RAN_HIGH, hwid_high.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
544
}
545

546 547
void ctu_can_fd_set_rx_tsop(struct ctucanfd_priv *priv,
			    enum ctu_can_fd_rx_settings_rtsop val)
548 549
{
	union ctu_can_fd_rx_status_rx_settings reg;
550

551
	reg.u32 = 0;
552
	reg.s.rtsop = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
553
	priv->write_reg(priv, CTU_CAN_FD_RX_STATUS, reg.u32);
554 555
}

556 557
void ctu_can_fd_read_rx_frame(struct ctucanfd_priv *priv,
			      struct canfd_frame *cf, u64 *ts)
558 559
{
	union ctu_can_fd_frame_form_w ffw;
Martin Jeřábek's avatar
Martin Jeřábek committed
560

Martin Jeřábek's avatar
Martin Jeřábek committed
561 562 563 564
	ffw.u32 = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
	ctu_can_fd_read_rx_frame_ffw(priv, cf, ts, ffw);
}

565
void ctu_can_fd_read_rx_frame_ffw(struct ctucanfd_priv *priv,
566 567
				  struct canfd_frame *cf, u64 *ts,
				  union ctu_can_fd_frame_form_w ffw)
Martin Jeřábek's avatar
Martin Jeřábek committed
568
{
569
	union ctu_can_fd_identifier_w idw;
570 571
	unsigned int i;
	enum ctu_can_fd_frame_form_w_ide ide;
Martin Jeřábek's avatar
Martin Jeřábek committed
572 573

	idw.u32 = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
574 575
	cf->can_id = 0;
	cf->flags = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
576

577
	/* BRS, ESI, RTR Flags */
Martin Jeřábek's avatar
Martin Jeřábek committed
578
	if (ffw.s.fdf == FD_CAN) {
579
		if (ffw.s.brs == BR_SHIFT)
580
			cf->flags |= CANFD_BRS;
Martin Jeřábek's avatar
Martin Jeřábek committed
581
		if (ffw.s.esi_rsv == ESI_ERR_PASIVE)
582
			cf->flags |= CANFD_ESI;
583
	} else if (ffw.s.rtr == RTR_FRAME) {
584
		cf->can_id |= CAN_RTR_FLAG;
585
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
586

587
	/* DLC */
Martin Jeřábek's avatar
Martin Jeřábek committed
588
	if (ffw.s.dlc <= 8) {
Martin Jeřábek's avatar
Martin Jeřábek committed
589
		cf->len = ffw.s.dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
590
	} else {
Martin Jeřábek's avatar
Martin Jeřábek committed
591
		if (ffw.s.fdf == FD_CAN)
592
			cf->len = (ffw.s.rwcnt - 3) << 2;
593 594 595 596
		else
			cf->len = 8;
	}

597
	ide = (enum ctu_can_fd_frame_form_w_ide)ffw.s.ide;
598
	ctu_can_fd_hwid_to_id(idw, &cf->can_id, ide);
Martin Jeřábek's avatar
Martin Jeřábek committed
599

600
	/* Timestamp */
Martin Jeřábek's avatar
Martin Jeřábek committed
601 602
	*ts = (u64)(priv->read_reg(priv, CTU_CAN_FD_RX_DATA));
	*ts |= ((u64)priv->read_reg(priv, CTU_CAN_FD_RX_DATA) << 32);
Martin Jeřábek's avatar
Martin Jeřábek committed
603

604
	/* Data */
605 606 607 608
	for (i = 0; i < cf->len; i += 4) {
		u32 data = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
		*(u32 *)(cf->data + i) = data;
	}
609 610
}

611 612
enum ctu_can_fd_tx_status_tx1s ctu_can_fd_get_tx_status(struct ctucanfd_priv
							*priv, u8 buf)
613 614
{
	union ctu_can_fd_tx_status reg;
615
	uint32_t status;
Martin Jeřábek's avatar
Martin Jeřábek committed
616 617

	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_TX_STATUS);
Martin Jeřábek's avatar
Martin Jeřábek committed
618

619
	switch (buf) {
620 621 622 623 624 625 626 627 628 629 630 631 632
	case CTU_CAN_FD_TXT_BUFFER_1:
		status = reg.s.tx1s;
		break;
	case CTU_CAN_FD_TXT_BUFFER_2:
		status = reg.s.tx2s;
		break;
	case CTU_CAN_FD_TXT_BUFFER_3:
		status = reg.s.tx3s;
		break;
	case CTU_CAN_FD_TXT_BUFFER_4:
		status = reg.s.tx4s;
		break;
	default:
633
		status = ~0;
634
	}
635
	return (enum ctu_can_fd_tx_status_tx1s)status;
636 637
}

638
bool ctu_can_fd_is_txt_buf_accessible(struct ctucanfd_priv *priv, u8 buf)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
639 640 641
{
	enum ctu_can_fd_tx_status_tx1s buf_status;

642
	buf_status = ctu_can_fd_get_tx_status(priv, buf);
643 644
	if (buf_status == TXT_RDY || buf_status == TXT_TRAN ||
	    buf_status == TXT_ABTP)
645
		return false;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
646 647 648 649

	return true;
}

650
bool ctu_can_fd_txt_buf_give_command(struct ctucanfd_priv *priv, u8 cmd, u8 buf)
651 652
{
	union ctu_can_fd_tx_command reg;
653

654
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
655

656 657 658 659 660 661 662 663 664 665 666 667 668
	switch (buf) {
	case CTU_CAN_FD_TXT_BUFFER_1:
		reg.s.txb1 = 1;
		break;
	case CTU_CAN_FD_TXT_BUFFER_2:
		reg.s.txb2 = 1;
		break;
	case CTU_CAN_FD_TXT_BUFFER_3:
		reg.s.txb3 = 1;
		break;
	case CTU_CAN_FD_TXT_BUFFER_4:
		reg.s.txb4 = 1;
		break;
669
	default:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
670 671
		return false;
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
672

Martin Jeřábek's avatar
Martin Jeřábek committed
673
	// TODO: use named constants for the command
674
	if (cmd & 0x1) {
675
		reg.s.txce = 1;
676
	} else if (cmd & 0x2) {
677
		reg.s.txcr = 1;
678
	} else if (cmd & 0x4) {
679
		reg.s.txca = 1;
680
	} else {
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
681
		return false;
682
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
683

Martin Jeřábek's avatar
Martin Jeřábek committed
684
	priv->write_reg(priv, CTU_CAN_FD_TX_COMMAND, reg.u32);
Martin Jeřábek's avatar
Martin Jeřábek committed
685
	return true;
686 687
}

688
void ctu_can_fd_set_txt_priority(struct ctucanfd_priv *priv, const u8 *prio)
689 690
{
	union ctu_can_fd_tx_priority reg;
691

692
	reg.u32 = 0;
693 694 695 696
	reg.s.txt1p = prio[0];
	reg.s.txt2p = prio[1];
	reg.s.txt3p = prio[2];
	reg.s.txt4p = prio[3];
Martin Jeřábek's avatar
Martin Jeřábek committed
697

Martin Jeřábek's avatar
Martin Jeřábek committed
698
	priv->write_reg(priv, CTU_CAN_FD_TX_PRIORITY, reg.u32);
699 700
}

701 702 703 704
static const enum ctu_can_fd_can_registers
	tx_buf_bases[CTU_CAN_FD_TXT_BUFFER_COUNT] = {
		CTU_CAN_FD_TXTB1_DATA_1, CTU_CAN_FD_TXTB2_DATA_1,
		CTU_CAN_FD_TXTB3_DATA_1, CTU_CAN_FD_TXTB4_DATA_1
Martin Jeřábek's avatar
Martin Jeřábek committed
705 706
};

707 708 709
bool ctu_can_fd_insert_frame(struct ctucanfd_priv *priv,
			     const struct canfd_frame *cf, u64 ts, u8 buf,
			     bool isfdf)
710
{
711
	enum ctu_can_fd_can_registers buf_base;
712 713
	union ctu_can_fd_frame_form_w ffw;
	union ctu_can_fd_identifier_w idw;
714
	u8 dlc;
715
	unsigned int i;
Martin Jeřábek's avatar
Martin Jeřábek committed
716

717 718
	ffw.u32 = 0;
	idw.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
719 720

	if (buf >= CTU_CAN_FD_TXT_BUFFER_COUNT)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
721
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
722
	buf_base = tx_buf_bases[buf];
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
723

Martin Jeřábek's avatar
Martin Jeřábek committed
724
	if (!ctu_can_fd_is_txt_buf_accessible(priv, buf))
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
725 726
		return false;

Martin Jeřábek's avatar
Martin Jeřábek committed
727
	if (cf->can_id & CAN_RTR_FLAG)
728
		ffw.s.rtr = RTR_FRAME;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
729

Martin Jeřábek's avatar
Martin Jeřábek committed
730
	if (cf->can_id & CAN_EFF_FLAG)
Martin Jeřábek's avatar
Martin Jeřábek committed
731
		ffw.s.ide = EXTENDED;
732
	else
Martin Jeřábek's avatar
Martin Jeřábek committed
733
		ffw.s.ide = BASE;
Martin Jeřábek's avatar
Martin Jeřábek committed
734

735
	ffw.s.tbf = TIME_BASED;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
736

Martin Jeřábek's avatar
Martin Jeřábek committed
737
	idw = ctu_can_fd_id_to_hwid(cf->can_id);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
738

Martin Jeřábek's avatar
Martin Jeřábek committed
739
	if (!ctu_can_fd_len_to_dlc(cf->len, &dlc))
740 741
		return false;
	ffw.s.dlc = dlc;
742

Martin Jeřábek's avatar
Martin Jeřábek committed
743
	if (isfdf) {
Martin Jeřábek's avatar
Martin Jeřábek committed
744
		ffw.s.fdf = FD_CAN;
Martin Jeřábek's avatar
Martin Jeřábek committed
745 746
		if (cf->flags & CANFD_BRS)
			ffw.s.brs = BR_SHIFT;