ctu_can_fd_hw.c 19.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*******************************************************************************
 * 
 * CTU CAN FD IP Core
 * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
 * 
 * Project advisors and co-authors: 
 * 	Jiri Novak <jnovak@fel.cvut.cz>
 * 	Pavel Pisa <pisa@cmp.felk.cvut.cz>
 * 	Martin Jerabek <jerabma7@fel.cvut.cz>
 * 
 * Department of Measurement         (http://meas.fel.cvut.cz/)
 * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
 * Czech Technical University        (http://www.cvut.cz/)
 * 
 * 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.
 * 
 * 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
*******************************************************************************/

31 32
#ifndef __KERNEL__
# include "ctu_can_fd_linux_defs.h"
Martin Jeřábek's avatar
Martin Jeřábek committed
33 34
#else
# include <linux/can/dev.h>
35 36
#endif

37
#include "ctu_can_fd_frame.h"
38
//#include "ctu_can_fd_regs.h"
39
#include "ctu_can_fd_hw.h"
40

Martin Jeřábek's avatar
Martin Jeřábek committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
void ctu_can_fd_write32(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg,
			u32 val)
{
	iowrite32(val, (char *)priv->mem_base + reg);
}

void ctu_can_fd_write32_be(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg,
			u32 val)
{
	iowrite32(val, (char *)priv->mem_base + reg);
}

u32 ctu_can_fd_read32(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg)
{
	return ioread32((const char *)priv->mem_base + reg);
}

u32 ctu_can_fd_read32_be(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg)
{
	return ioread32be((const char *)priv->mem_base + reg);
}

/*
void ctu_can_fd_write16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg,
				      u16 val)
{
	iowrite16(val, (char *)priv->mem_base + reg);
}

void ctu_can_fd_write8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg,
				     u8 val)
{
	iowrite8(val, (char *)priv->mem_base + reg);
}
*/

/*
u16 ctu_can_fd_read16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg)
{
	return ioread16((const char *)priv->mem_base + reg);
}

u8 ctu_can_fd_read8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg)
{
	return ioread8((const char *)priv->mem_base + reg);
}
*/

static void ctu_can_fd_write_txt_buf(struct ctucanfd_priv *priv,
			      enum ctu_can_fd_regs buf_base,
			      u32 offset, u32 val)
{
	priv->write_reg(priv, buf_base + offset, val);
}


97

Martin Jeřábek's avatar
Martin Jeřábek committed
98
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
99
{
Martin Jeřábek's avatar
Martin Jeřábek committed
100 101
	union ctu_can_fd_identifier_w hwid;
	hwid.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
102 103

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

106
		// getting lowest 18 bits, replace with sth nicer...
Martin Jeřábek's avatar
Martin Jeřábek committed
107
		hwid.s.identifier_ext = (id & 0x3FFFF);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
108
	}else
Martin Jeřábek's avatar
Martin Jeřábek committed
109 110
		hwid.s.identifier_base = id & CAN_SFF_MASK;
	return hwid;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
111
}
Martin Jeřábek's avatar
Martin Jeřábek committed
112 113

// TODO: rename or do not depend on previous value of id
114
static inline void ctu_can_fd_hwid_to_id(union ctu_can_fd_identifier_w hwid,
115 116 117 118 119 120
					 canid_t *id,
					 enum ctu_can_fd_frame_form_w_id_type type)
{	
	// Preserve flags which we dont set
	*id &= ~(CAN_EFF_FLAG | CAN_EFF_MASK);
	
121
	if (type == EXTENDED){
122 123 124 125 126
		*id |= CAN_EFF_FLAG;
		*id |= hwid.s.identifier_base << 18;
		*id |= hwid.s.identifier_ext;
	}else
		*id = hwid.s.identifier_base;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
127 128
}

129

130
// TODO: use can_len2dlc
131 132
static bool ctu_can_fd_len_to_dlc(u8 len, u8 *dlc)
{
133 134 135
	*dlc = can_len2dlc(len);
	return true;
	/*
Martin Jeřábek's avatar
Martin Jeřábek committed
136 137 138 139 140 141 142 143 144
	if (unlikely(len > 64)) {
		*dlc = 0;
		return false;
	} else {
		*dlc = can_len2dlc(len);
		if (unlikely(*dlc == can_len2dlc(len-1))) {
			*dlc = 0;
			return false;
		}
145 146
	}*/

Martin Jeřábek's avatar
Martin Jeřábek committed
147
	/*
148
	if (len <= 8){
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
		*dlc = len;
		goto exit_ok;
	}

	switch (len){
	case 12 : *dlc = 0x9;
	break;
	case 16 : *dlc = 0xA;
	break;
	case 20 : *dlc = 0xB;
	break;
	case 24 : *dlc = 0xC;
	break;
	case 32 : *dlc = 0xD;
	break;
	case 48 : *dlc = 0xE;
	break;
	case 64 : *dlc = 0xF;
	break;
	default : *dlc = 0x0;
	}
	
171
	if (*dlc == 0)
172
		return false;
173
exit_ok:
Martin Jeřábek's avatar
Martin Jeřábek committed
174
	*/
175 176 177 178
	return true;
}


179
bool ctu_can_fd_check_access(struct ctucanfd_priv *priv)
180 181
{
	union ctu_can_fd_device_id_version reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
182
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
183
	
184 185
	if (reg.s.device_id != CTU_CAN_FD_ID)
		return false;
186
		
187
	return true;
188 189
}

190
u32 ctu_can_fd_get_version(struct ctucanfd_priv *priv)
191 192
{
	union ctu_can_fd_device_id_version reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
193
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
194
	return reg.s.ver_major * 10 + reg.s.ver_minor;
195 196
}

197
void ctu_can_fd_enable(struct ctucanfd_priv *priv, bool enable)
198 199
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
200
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
201
	reg.s.ena = enable ? ENABLED : DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
202 203 204 205 206 207 208 209 210
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
}

void ctu_can_fd_reset(struct ctucanfd_priv *priv)
{
	union ctu_can_fd_mode_command_status_settings mode;
	mode.s.rst = 1;
	/* it does not matter that we overwrite the rest of the reg - we're resetting */
	priv->write_reg(priv, CTU_CAN_FD_MODE, mode.u32);
211 212
}

213
bool ctu_can_fd_set_ret_limit(struct ctucanfd_priv *priv, bool enable, u8 limit)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
214 215
{
	union ctu_can_fd_mode_command_status_settings reg;
216 217 218 219
	
	if (limit > CTU_CAN_FD_RETR_MAX)
		return false;
 	
Martin Jeřábek's avatar
Martin Jeřábek committed
220
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
221
	reg.s.rtrle = enable ? RTRLE_ENABLED : RTRLE_DISABLED;
222
	reg.s.rtr_th = limit & 0xF;
Martin Jeřábek's avatar
Martin Jeřábek committed
223
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
224
	return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
225 226
}

227
void ctu_can_fd_set_mode_reg(struct ctucanfd_priv *priv, const struct can_ctrlmode *mode)
228
{
Martin Jeřábek's avatar
Martin Jeřábek committed
229
	u32 flags = mode->flags;
230
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
231
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
232 233
	
	if (mode->mask & CAN_CTRLMODE_LOOPBACK)
Martin Jeřábek's avatar
Martin Jeřábek committed
234
		reg.s.int_loop = flags & CAN_CTRLMODE_LOOPBACK ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
235
					INT_LOOP_ENABLED : INT_LOOP_DISABLED;
236 237
	
	if (mode->mask & CAN_CTRLMODE_LISTENONLY)
Martin Jeřábek's avatar
Martin Jeřábek committed
238
		reg.s.lom = flags & CAN_CTRLMODE_LISTENONLY ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
239
					LOM_ENABLED : LOM_DISABLED;
240 241
	
	if (mode->mask & CAN_CTRLMODE_3_SAMPLES)
Martin Jeřábek's avatar
Martin Jeřábek committed
242
		reg.s.tsm = flags & CAN_CTRLMODE_3_SAMPLES ?
243
				TSM_ENABLE : TSM_DISABLE;
244 245
	
	if (mode->mask & CAN_CTRLMODE_FD)
Martin Jeřábek's avatar
Martin Jeřábek committed
246
		reg.s.fde = flags & CAN_CTRLMODE_FD ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
247
				FDE_ENABLE : FDE_DISABLE;
248 249
	
	if (mode->mask & CAN_CTRLMODE_PRESUME_ACK)
Martin Jeřábek's avatar
Martin Jeřábek committed
250
		reg.s.stm = flags & CAN_CTRLMODE_PRESUME_ACK ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
251
				STM_ENABLED : STM_DISABLED;
252 253
	
	if (mode->mask & CAN_CTRLMODE_FD_NON_ISO)
Martin Jeřábek's avatar
Martin Jeřábek committed
254
		reg.s.fd_type = flags & CAN_CTRLMODE_FD_NON_ISO ?
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
255
				NON_ISO_FD : ISO_FD;
256

Martin Jeřábek's avatar
Martin Jeřábek committed
257
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
258 259
}

260
void ctu_can_fd_rel_rx_buf(struct ctucanfd_priv *priv)
261 262
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
263
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
264
	reg.s.rrb = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
265
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
266 267
}

268
void ctu_can_fd_clr_overrun_flag(struct ctucanfd_priv *priv)
269 270
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
271
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
272
	reg.s.cdo = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
273
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
274 275
}

276
void ctu_can_fd_abort_tx(struct ctucanfd_priv *priv)
277 278
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
279
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
280
	reg.s.at = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
281
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
282 283
}

Martin Jeřábek's avatar
Martin Jeřábek committed
284 285
// TODO: rather than set(value, mask) interface, provide native set(val), clr(val)
//       interface to potentially avoid unnecessary write
286
static void ctu_can_fd_int_conf(struct ctucanfd_priv *priv, enum ctu_can_fd_regs sreg,
287
				enum ctu_can_fd_regs creg, 
288 289
				union ctu_can_fd_int_stat mask,
				union ctu_can_fd_int_stat val)
290
{
291
	//union ctu_can_fd_int_stat reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
292
	//reg.u32 = priv->read_reg(priv, sreg);
293
	
Martin Jeřábek's avatar
Martin Jeřábek committed
294 295
	priv->write_reg(priv, sreg, mask.u32 & val.u32);
	priv->write_reg(priv, creg, mask.u32 & (~val.u32));
296 297
}

298
void ctu_can_fd_int_ena(struct ctucanfd_priv *priv, union ctu_can_fd_int_stat mask,
299
			union ctu_can_fd_int_stat val)
300
{
301
	ctu_can_fd_int_conf(priv, CTU_CAN_FD_INT_ENA_SET, CTU_CAN_FD_INT_ENA_CLR,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
302
				mask, val);
303 304
}

305
void ctu_can_fd_int_mask(struct ctucanfd_priv *priv, union ctu_can_fd_int_stat mask,
306
			 union ctu_can_fd_int_stat val)
307
{
308
	ctu_can_fd_int_conf(priv, CTU_CAN_FD_INT_MASK_SET, CTU_CAN_FD_INT_MASK_CLR,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
309 310 311
				mask, val);
}

312
void ctu_can_fd_set_mode(struct ctucanfd_priv *priv, const struct can_ctrlmode *mode)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
313
{
314
	ctu_can_fd_set_mode_reg(priv, mode);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
315 316 317
	
	// One shot mode supported indirectly via Retransmitt limit
	if (mode->mask & CAN_CTRLMODE_ONE_SHOT)
Martin Jeřábek's avatar
Martin Jeřábek committed
318
		ctu_can_fd_set_ret_limit(priv, !!(mode->flags & CAN_CTRLMODE_ONE_SHOT), 0);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
319 320

	// Bus error reporting -> Allow Error interrupt
Martin Jeřábek's avatar
Martin Jeřábek committed
321 322 323 324 325 326 327
	if (mode->mask & CAN_CTRLMODE_BERR_REPORTING) {
		union ctu_can_fd_int_stat ena, mask;
		ena.u32 = mask.u32 = 0;
		ena.s.bei = !!(mode->flags & CAN_CTRLMODE_ONE_SHOT);
		mask.s.bei = 1;
		ctu_can_fd_int_ena(priv, ena, mask);
	}
328 329
}

Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
330

331
const struct can_bittiming_const ctu_can_fd_bit_timing_max = {
332
	.name = "ctu_can_fd",
333 334 335 336 337 338 339 340 341 342
	.tseg1_min = 2,
	.tseg1_max = 190,
	.tseg2_min = 1,
	.tseg2_max = 63,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

343
const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = {
344
	.name = "ctu_can_fd",
345 346 347 348 349 350 351 352 353 354
	.tseg1_min = 2,
	.tseg1_max = 94,
	.tseg2_min = 1,
	.tseg2_max = 31,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

355
void ctu_can_fd_set_nom_bittiming(struct ctucanfd_priv *priv,
356
				  const struct can_bittiming *nbt)
357 358 359
{
	union ctu_can_fd_btr btr;
	btr.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
360 361 362 363 364
	btr.s.prop = nbt->prop_seg;
	btr.s.ph1 = nbt->phase_seg1;
	btr.s.ph2 = nbt->phase_seg2;
	btr.s.brp = nbt->brp;
	btr.s.sjw = nbt->sjw;
365

Martin Jeřábek's avatar
Martin Jeřábek committed
366
	priv->write_reg(priv, CTU_CAN_FD_BTR, btr.u32);
367 368
}

369
void ctu_can_fd_set_data_bittiming(struct ctucanfd_priv *priv,
370
				   const struct can_bittiming *dbt)
371 372 373
{
	union ctu_can_fd_btr_fd btr_fd;
	btr_fd.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
374 375 376 377 378
	btr_fd.s.prop_fd = dbt->prop_seg;
	btr_fd.s.ph1_fd = dbt->phase_seg1;
	btr_fd.s.ph2_fd = dbt->phase_seg2;
	btr_fd.s.brp_fd = dbt->brp;
	btr_fd.s.sjw_fd = dbt->sjw;
379
	
Martin Jeřábek's avatar
Martin Jeřábek committed
380
	priv->write_reg(priv, CTU_CAN_FD_BTR_FD, btr_fd.u32);
381 382
}

383
void ctu_can_fd_set_err_limits(struct ctucanfd_priv *priv, u8 ewl, u8 erp)
384 385 386
{
	union ctu_can_fd_ewl_erp_fault_state reg;
	reg.u32 = 0;
387 388
	reg.s.ewl_limit = ewl;
	reg.s.erp_limit = erp;
389 390
	// era, bof, erp are read-only
	
Martin Jeřábek's avatar
Martin Jeřábek committed
391
	priv->write_reg(priv, CTU_CAN_FD_EWL, reg.u32);
392 393
}

Martin Jeřábek's avatar
Martin Jeřábek committed
394
void ctu_can_fd_read_err_ctrs(struct ctucanfd_priv *priv, struct can_berr_counter *ctr)
395 396 397
{
	union ctu_can_fd_rxc_txc reg;
	
Martin Jeřábek's avatar
Martin Jeřábek committed
398
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_RXC);
399 400
	ctr->txerr = reg.s.rxc_val;
	ctr->rxerr = reg.s.txc_val;
401 402
}

403
enum can_state ctu_can_fd_read_error_state(struct ctucanfd_priv *priv)
404 405
{
	union ctu_can_fd_ewl_erp_fault_state reg;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
406 407
	union ctu_can_fd_rxc_txc err;

Martin Jeřábek's avatar
Martin Jeřábek committed
408 409
	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
410

411
	if (reg.s.era){
Martin Jeřábek's avatar
Martin Jeřábek committed
412
		if (reg.s.ewl_limit > err.s.rxc_val && reg.s.ewl_limit > err.s.txc_val)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
413 414 415
			return CAN_STATE_ERROR_ACTIVE;
		else
			return CAN_STATE_ERROR_WARNING;
416
	}else if (reg.s.erp)
417
		return CAN_STATE_ERROR_PASSIVE;
418
	else if (reg.s.bof)
419
		return CAN_STATE_BUS_OFF;
Martin Jeřábek's avatar
Martin Jeřábek committed
420 421
	WARN(true, "Invalid error state");
	return CAN_STATE_ERROR_PASSIVE;
422 423
}

424
void ctu_can_fd_set_err_ctrs(struct ctucanfd_priv *priv, const struct can_berr_counter *ctr)
425 426 427
{
	union ctu_can_fd_ctr_pres reg;
	reg.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
428

429 430
	reg.s.ctpv = ctr->txerr;
	reg.s.ptx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
431
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
432

433 434 435
	reg.s.ctpv = ctr->rxerr;
	reg.s.ptx = 0;
	reg.s.prx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
436
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
437 438 439
}


440
bool ctu_can_fd_get_mask_filter_support(struct ctucanfd_priv *priv, u8 fnum)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
441 442
{
	union ctu_can_fd_filter_control_filter_status reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
443
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
444

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

	return false;
}

460
bool ctu_can_fd_get_range_filter_support(struct ctucanfd_priv *priv)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
461 462
{
	union ctu_can_fd_filter_control_filter_status reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
463
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
464

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

	return false;
}

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

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

	if (enable)
		val = 1;

Martin Jeřábek's avatar
Martin Jeřábek committed
486
	creg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Martin Jeřábek's avatar
Martin Jeřábek committed
487 488
	//maddr = 0;
	//vaddr = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
489 490

	switch (fnum){
491
	case CTU_CAN_FD_FILTER_A :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
492 493
		maddr = CTU_CAN_FD_FILTER_A_MASK;
		vaddr = CTU_CAN_FD_FILTER_A_VAL;	
494 495 496 497
		creg.s.fanb = val;
		creg.s.fane = val;
		creg.s.fafb = val;
		creg.s.fafe = val;	
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
498
	break;
499
	case CTU_CAN_FD_FILTER_B :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
500 501
		maddr = CTU_CAN_FD_FILTER_B_MASK;
		vaddr = CTU_CAN_FD_FILTER_B_VAL;
502 503 504 505
		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
506
	break;
507
	case CTU_CAN_FD_FILTER_C :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
508 509
		maddr = CTU_CAN_FD_FILTER_C_MASK;
		vaddr = CTU_CAN_FD_FILTER_C_VAL;
510 511 512 513
		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
514 515 516 517 518
	break;
	default:
		return false;
	}

Martin Jeřábek's avatar
Martin Jeřábek committed
519 520
	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
521 522 523
	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
524 525 526
	return true;
}

527
void ctu_can_fd_set_range_filter(struct ctucanfd_priv *priv, canid_t low_th,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
528 529
				 canid_t high_th, bool enable)
{
530 531 532 533
	union ctu_can_fd_identifier_w hwid_low;	
	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
534 535
	hwid_low = ctu_can_fd_id_to_hwid(low_th);
	hwid_high = ctu_can_fd_id_to_hwid(high_th);
536

Martin Jeřábek's avatar
Martin Jeřábek committed
537
	creg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
538
	
539 540 541 542 543
	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
544 545 546
	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
547
}
548

549
void ctu_can_fd_set_rx_tsop(struct ctucanfd_priv *priv, enum ctu_can_fd_rx_settings_rtsop val)
550 551 552
{
	union ctu_can_fd_rx_status_rx_settings reg;
	reg.u32 = 0;
553
	reg.s.rtsop = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
554
	priv->write_reg(priv, CTU_CAN_FD_RX_STATUS, reg.u32);
555 556
}

Martin Jeřábek's avatar
Martin Jeřábek committed
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 561 562 563 564 565 566
	
	ffw.u32 = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
	ctu_can_fd_read_rx_frame_ffw(priv, cf, ts, ffw);
}

void ctu_can_fd_read_rx_frame_ffw(struct ctucanfd_priv *priv, struct canfd_frame *cf, u64 *ts, union ctu_can_fd_frame_form_w ffw)
{
567
	union ctu_can_fd_identifier_w idw;
Martin Jeřábek's avatar
Martin Jeřábek committed
568
	unsigned i;
Martin Jeřábek's avatar
Martin Jeřábek committed
569 570

	idw.u32 = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
571 572 573 574
	cf->can_id = 0;
	cf->flags = 0;
	
	// BRS, ESI, RTR Flags
Martin Jeřábek's avatar
Martin Jeřábek committed
575
	if (ffw.s.fr_type == FD_CAN) {
576
		if (ffw.s.brs == BR_SHIFT)
577
			cf->flags |= CANFD_BRS;
578
		if (ffw.s.esi_resvd == ESI_ERR_PASIVE)
579
			cf->flags |= CANFD_ESI;
Martin Jeřábek's avatar
Martin Jeřábek committed
580
	} else if (ffw.s.rtr == RTR_FRAME)
581 582 583
		cf->can_id |= CAN_RTR_FLAG;
	
	// DLC
Martin Jeřábek's avatar
Martin Jeřábek committed
584
	if (ffw.s.dlc <= 8) {
Martin Jeřábek's avatar
Martin Jeřábek committed
585
		cf->len = ffw.s.dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
586
	} else {
587 588
		if (ffw.s.fr_type == FD_CAN)
			cf->len = (ffw.s.rwcnt - 3) << 2;
589 590 591 592
		else
			cf->len = 8;
	}

Martin Jeřábek's avatar
Martin Jeřábek committed
593
	ctu_can_fd_hwid_to_id(idw, &cf->can_id, (enum ctu_can_fd_frame_form_w_id_type) ffw.s.id_type);
594 595
	
	// Timestamp
Martin Jeřábek's avatar
Martin Jeřábek committed
596 597
	*ts = (u64)(priv->read_reg(priv, CTU_CAN_FD_RX_DATA));
	*ts |= ((u64)priv->read_reg(priv, CTU_CAN_FD_RX_DATA) << 32);
598 599
	
	// Data
600 601 602 603 604
	for (i = 0; i < cf->len; i += 4) {
		u32 data = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
		data = be32_to_cpu(data); // TODO: remove when the core is fixed
		*(u32 *)(cf->data + i) = data;
	}
605 606
}

607
enum ctu_can_fd_tx_status_tx1s ctu_can_fd_get_tx_status(struct ctucanfd_priv *priv, u8 buf)
608 609
{
	union ctu_can_fd_tx_status reg;
610
	uint32_t status;
Martin Jeřábek's avatar
Martin Jeřábek committed
611 612 613

	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_TX_STATUS);
	
614
	switch (buf) {
615
	case CTU_CAN_FD_TXT_BUFFER_1 : status = reg.s.tx1s;
616
	break;
617
	case CTU_CAN_FD_TXT_BUFFER_2 : status = reg.s.tx2s;
618
	break;
619
	case CTU_CAN_FD_TXT_BUFFER_3 : status = reg.s.tx3s;
620
	break;
621
	case CTU_CAN_FD_TXT_BUFFER_4 : status = reg.s.tx4s;
622 623
	break;
	default :
624
		status = ~0;
625
	}
626
	return (enum ctu_can_fd_tx_status_tx1s) status;
627 628
}

629
bool ctu_can_fd_is_txt_buf_accessible(struct ctucanfd_priv *priv, u8 buf)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
630 631 632
{
	enum ctu_can_fd_tx_status_tx1s buf_status;

633
	buf_status = ctu_can_fd_get_tx_status(priv, buf);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
634
	if (buf_status == TXT_RDY || buf_status == TXT_TRAN 
Martin Jeřábek's avatar
Martin Jeřábek committed
635
		|| buf_status == TXT_ABTP)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
636 637 638 639 640
 		return false;

	return true;
}

641
bool ctu_can_fd_txt_buf_give_command(struct ctucanfd_priv *priv, u8 cmd, u8 buf)
642 643 644 645
{
	union ctu_can_fd_tx_command reg;
	reg.u32 = 0;
	
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
646
	switch (buf){
Martin Jeřábek's avatar
Martin Jeřábek committed
647
	case CTU_CAN_FD_TXT_BUFFER_1: reg.s.txi1 = 1;
648
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
649
	case CTU_CAN_FD_TXT_BUFFER_2: reg.s.txi2 = 1;
650
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
651
	case CTU_CAN_FD_TXT_BUFFER_3: reg.s.txi3 = 1;
652
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
653
	case CTU_CAN_FD_TXT_BUFFER_4: reg.s.txi4 = 1;
654
	break;
655
	default:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
656 657
		return false;
	}
658
	
Martin Jeřábek's avatar
Martin Jeřábek committed
659
	// TODO: use named constants for the command
660
	if (cmd & 0x1) {
661
		reg.s.txce = 1;
662
	} else if (cmd & 0x2) {
663
		reg.s.txcr = 1;
664
	} else if (cmd & 0x4) {
665
		reg.s.txca = 1;
666
	} else {
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
667
		return false;
668 669
	}
	
Martin Jeřábek's avatar
Martin Jeřábek committed
670
	priv->write_reg(priv, CTU_CAN_FD_TX_COMMAND, reg.u32);
Martin Jeřábek's avatar
Martin Jeřábek committed
671
	return true;
672 673
}

674
void ctu_can_fd_set_txt_priority(struct ctucanfd_priv *priv, const u8 *prio)
675 676 677
{
	union ctu_can_fd_tx_priority reg;
	reg.u32 = 0;
678 679 680 681
	reg.s.txt1p = prio[0];
	reg.s.txt2p = prio[1];
	reg.s.txt3p = prio[2];
	reg.s.txt4p = prio[3];
682
	
Martin Jeřábek's avatar
Martin Jeřábek committed
683
	priv->write_reg(priv, CTU_CAN_FD_TX_PRIORITY, reg.u32);
684 685
}

Martin Jeřábek's avatar
Martin Jeřábek committed
686 687 688 689 690 691 692
static const enum ctu_can_fd_regs 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
};

bool ctu_can_fd_insert_frame(struct ctucanfd_priv *priv, const struct canfd_frame *cf, u64 ts,
				u8 buf, bool isfdf)
693
{
Martin Jeřábek's avatar
Martin Jeřábek committed
694
	enum ctu_can_fd_regs buf_base;
695 696
	union ctu_can_fd_frame_form_w ffw;
	union ctu_can_fd_identifier_w idw;
697
	u8 dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
698
	unsigned i;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
699
	
700 701
	ffw.u32 = 0;
	idw.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
702 703

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

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

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

Martin Jeřábek's avatar
Martin Jeřábek committed
713
	if (cf->can_id & CAN_EFF_FLAG)
714
		ffw.s.id_type = EXTENDED;
715
	else
716
		ffw.s.id_type = BASE;
717 718
	
	ffw.s.tbf = TIME_BASED;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
719

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

Martin Jeřábek's avatar
Martin Jeřábek committed
722
	if (!ctu_can_fd_len_to_dlc(cf->len, &dlc))
723
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
724

725
	ffw.s.dlc = dlc;
726

727
	// Larger data chunks and the ones where bit rate should be shifted
728 729 730 731 732
	// are sent as CAN FD Frames. TODO: Think here, and discuss this with Martin.
	// How does the Socket CAN distinguish beween normal and FD Frame (without BRS)
	// Once BRS flag is present it is clear. Without it, we dont know whether
	// 8 byte frame should be CAN FD Frame without bit rate shifted or CAN Frame
	// So we send FD Frame only if BRS present or higher length than 8 ...
Martin Jeřábek's avatar
Martin Jeřábek committed
733 734
	// MJ: via can_is_canfd_skb(skb) - it basically checks the skb size
	if (isfdf) {
735
		ffw.s.fr_type = FD_CAN;
Martin Jeřábek's avatar
Martin Jeřábek committed
736 737
		if (cf->flags & CANFD_BRS)
			ffw.s.brs = BR_SHIFT;
738
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
739

740 741
	ctu_can_fd_write_txt_buf(priv, buf_base, CTU_CAN_FD_FRAME_FORM_W, ffw.u32);
	ctu_can_fd_write_txt_buf(priv, buf_base, CTU_CAN_FD_IDENTIFIER_W, idw.u32);
742
	
743 744
	ctu_can_fd_write_txt_buf(priv, buf_base, CTU_CAN_FD_TIMESTAMP_L_W, (u32)(ts));
	ctu_can_fd_write_txt_buf(priv, buf_base, CTU_CAN_FD_TIMESTAMP_U_W, (u32)(ts >> 32));
745
	
Martin Jeřábek's avatar
Martin Jeřábek committed
746 747
	if (!(cf->can_id & CAN_RTR_FLAG)) {
		// be32_to_cpup?
748 749 750
		for (i = 0; i < cf->len; i += 4) {
			u32 data = *(u32 *)(cf->data + i);
			data = cpu_to_be32(data); // TODO: remove when the core is fixed
Martin Jeřábek's avatar
Martin Jeřábek committed
751
			ctu_can_fd_write_txt_buf(priv, buf_base, CTU_CAN_FD_DATA_1_4_W + i,
752 753
								data);
		}
Martin Jeřábek's avatar
Martin Jeřábek committed
754
	}
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
755 756

	return true;
757 758 759 760
}

// TODO: AL_CAPTURE and ERROR_CAPTURE