ctu_can_fd_hw.c 20.2 KB
Newer Older
1
/*******************************************************************************
Martin Jeřábek's avatar
Martin Jeřábek committed
2
 *
3
 * CTU CAN FD IP Core
4
 * Copyright (C) 2015-2018
Martin Jeřábek's avatar
Martin Jeřábek committed
5
 *
6 7
 * Authors:
 *     Ondrej Ille <ondrej.ille@gmail.com>
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
8
 *     Martin Jerabek <martin.jerabek01@gmail.com>
Martin Jeřábek's avatar
Martin Jeřábek committed
9 10
 *
 * Project advisors:
11 12
 * 	Jiri Novak <jnovak@fel.cvut.cz>
 * 	Pavel Pisa <pisa@cmp.felk.cvut.cz>
Martin Jeřábek's avatar
Martin Jeřábek committed
13
 *
14 15 16
 * 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
17
 *
18 19 20 21
 * 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
22
 *
23 24 25 26
 * 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
27
 *
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
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Martin Jeřábek's avatar
Martin Jeřábek committed
31
 *
32 33
*******************************************************************************/

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

40
#include "ctu_can_fd_frame.h"
41
//#include "ctu_can_fd_regs.h"
42
#include "ctu_can_fd_hw.h"
43

Martin Jeřábek's avatar
Martin Jeřábek committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
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,
Martin Jeřábek's avatar
Martin Jeřábek committed
68
					  u16 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
69 70 71 72 73
{
	iowrite16(val, (char *)priv->mem_base + reg);
}

void ctu_can_fd_write8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg,
Martin Jeřábek's avatar
Martin Jeřábek committed
74
					 u8 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
	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,
Martin Jeřábek's avatar
Martin Jeřábek committed
93 94
				  enum ctu_can_fd_regs buf_base,
				  u32 offset, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
95 96 97 98 99
{
	priv->write_reg(priv, buf_base + offset, val);
}


100

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

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

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

// TODO: rename or do not depend on previous value of id
117
static inline void ctu_can_fd_hwid_to_id(union ctu_can_fd_identifier_w hwid,
118
					 canid_t *id,
Martin Jeřábek's avatar
Martin Jeřábek committed
119
					 enum ctu_can_fd_frame_form_w_ide type)
Martin Jeřábek's avatar
Martin Jeřábek committed
120
{
121 122
	// Preserve flags which we dont set
	*id &= ~(CAN_EFF_FLAG | CAN_EFF_MASK);
Martin Jeřábek's avatar
Martin Jeřábek committed
123

124
	if (type == EXTENDED){
125 126 127 128 129
		*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
130 131
}

132

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

Martin Jeřábek's avatar
Martin Jeřábek committed
150
	/*
151
	if (len <= 8){
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		*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;
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
173

174
	if (*dlc == 0)
175
		return false;
176
exit_ok:
Martin Jeřábek's avatar
Martin Jeřábek committed
177
	*/
178 179 180 181
	return true;
}


182
bool ctu_can_fd_check_access(struct ctucanfd_priv *priv)
183 184
{
	union ctu_can_fd_device_id_version reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
185
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
Martin Jeřábek's avatar
Martin Jeřábek committed
186

187 188
	if (reg.s.device_id != CTU_CAN_FD_ID)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
189

190
	return true;
191 192
}

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

200
void ctu_can_fd_enable(struct ctucanfd_priv *priv, bool enable)
201 202
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
203
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
204
	reg.s.ena = enable ? ENABLED : DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
205 206 207 208 209 210 211 212 213
	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);
214 215
}

216
bool ctu_can_fd_set_ret_limit(struct ctucanfd_priv *priv, bool enable, u8 limit)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
217 218
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
219

220 221
	if (limit > CTU_CAN_FD_RETR_MAX)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
222

Martin Jeřábek's avatar
Martin Jeřábek committed
223
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
224
	reg.s.rtrle = enable ? RTRLE_ENABLED : RTRLE_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
225
	reg.s.rtrth = limit & 0xF;
Martin Jeřábek's avatar
Martin Jeřábek committed
226
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
227
	return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
228 229
}

230
void ctu_can_fd_set_mode_reg(struct ctucanfd_priv *priv, const struct can_ctrlmode *mode)
231
{
Martin Jeřábek's avatar
Martin Jeřábek committed
232
	u32 flags = mode->flags;
233
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
234
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
Martin Jeřábek's avatar
Martin Jeřábek committed
235

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

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

244
	if (mode->mask & CAN_CTRLMODE_3_SAMPLES)
Martin Jeřábek's avatar
Martin Jeřábek committed
245
		reg.s.tsm = flags & CAN_CTRLMODE_3_SAMPLES ?
246
				TSM_ENABLE : TSM_DISABLE;
Martin Jeřábek's avatar
Martin Jeřábek committed
247

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

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

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

Martin Jeřábek's avatar
Martin Jeřábek committed
260
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
261 262
}

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

265
void ctu_can_fd_rel_rx_buf(struct ctucanfd_priv *priv)
266 267
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
268
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
269
	reg.s.rrb = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
270
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
271 272
}

273
void ctu_can_fd_clr_overrun_flag(struct ctucanfd_priv *priv)
274 275
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
276
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
277
	reg.s.cdo = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
278
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
279 280
}

281
void ctu_can_fd_abort_tx(struct ctucanfd_priv *priv)
282 283
{
	union ctu_can_fd_mode_command_status_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
284
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
Martin Jeřábek's avatar
Martin Jeřábek committed
285
	reg.s.abt = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
286
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
287 288
}

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

Martin Jeřábek's avatar
Martin Jeřábek committed
299 300
	priv->write_reg(priv, sreg, mask.u32 & val.u32);
	priv->write_reg(priv, creg, mask.u32 & (~val.u32));
301 302
}

303
void ctu_can_fd_int_ena(struct ctucanfd_priv *priv, union ctu_can_fd_int_stat mask,
304
			union ctu_can_fd_int_stat val)
305
{
306
	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
307
				mask, val);
308 309
}

310
void ctu_can_fd_int_mask(struct ctucanfd_priv *priv, union ctu_can_fd_int_stat mask,
311
			 union ctu_can_fd_int_stat val)
312
{
313
	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
314 315 316
				mask, val);
}

317
void ctu_can_fd_set_mode(struct ctucanfd_priv *priv, const struct can_ctrlmode *mode)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
318
{
319
	ctu_can_fd_set_mode_reg(priv, mode);
Martin Jeřábek's avatar
Martin Jeřábek committed
320

Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
321 322
	// One shot mode supported indirectly via Retransmitt limit
	if (mode->mask & CAN_CTRLMODE_ONE_SHOT)
Martin Jeřábek's avatar
Martin Jeřábek committed
323
		ctu_can_fd_set_ret_limit(priv, !!(mode->flags & CAN_CTRLMODE_ONE_SHOT), 0);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
324 325

	// Bus error reporting -> Allow Error interrupt
Martin Jeřábek's avatar
Martin Jeřábek committed
326 327 328 329 330 331 332
	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);
	}
333 334
}

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

336
const struct can_bittiming_const ctu_can_fd_bit_timing_max = {
337
	.name = "ctu_can_fd",
338 339 340 341 342 343 344 345 346 347
	.tseg1_min = 2,
	.tseg1_max = 190,
	.tseg2_min = 1,
	.tseg2_max = 63,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

348
const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = {
349
	.name = "ctu_can_fd",
350 351 352 353 354 355 356 357 358 359
	.tseg1_min = 2,
	.tseg1_max = 94,
	.tseg2_min = 1,
	.tseg2_max = 31,
	.sjw_max = 31,
	.brp_min = 1,
	.brp_max = 255,
	.brp_inc = 1,
};

360
void ctu_can_fd_set_nom_bittiming(struct ctucanfd_priv *priv,
361
				  struct can_bittiming *nbt)
362 363
{
	union ctu_can_fd_btr btr;
364

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
	/*
	 * The timing calculation functions have only constraints on tseg1,
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
	 * 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.
	 */
	u32 prop_seg = nbt->prop_seg;
	u32 phase_seg1 = nbt->phase_seg1;
	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;
381 382
	btr.s.prop = prop_seg;
	btr.s.ph1 = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
383 384 385
	btr.s.ph2 = nbt->phase_seg2;
	btr.s.brp = nbt->brp;
	btr.s.sjw = nbt->sjw;
386

Martin Jeřábek's avatar
Martin Jeřábek committed
387
	priv->write_reg(priv, CTU_CAN_FD_BTR, btr.u32);
388 389
}

390
void ctu_can_fd_set_data_bittiming(struct ctucanfd_priv *priv,
391
				   struct can_bittiming *dbt)
392 393
{
	union ctu_can_fd_btr_fd btr_fd;
394

395 396 397 398 399 400 401 402 403 404 405 406 407 408
	/*
	 * The timing calculation functions have only constraints on tseg1,
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
	 * 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.
	 */
	u32 prop_seg = dbt->prop_seg;
	u32 phase_seg1 = dbt->phase_seg1;
	if (phase_seg1 > 31) {
		prop_seg += phase_seg1 - 31;
		phase_seg1 = 31;
		dbt->prop_seg = prop_seg;
		dbt->phase_seg1 = phase_seg1;
	}
409

410
	btr_fd.u32 = 0;
411 412
	btr_fd.s.prop_fd = prop_seg;
	btr_fd.s.ph1_fd = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
413 414 415
	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
416

Martin Jeřábek's avatar
Martin Jeřábek committed
417
	priv->write_reg(priv, CTU_CAN_FD_BTR_FD, btr_fd.u32);
418 419
}

420
void ctu_can_fd_set_err_limits(struct ctucanfd_priv *priv, u8 ewl, u8 erp)
421 422 423
{
	union ctu_can_fd_ewl_erp_fault_state reg;
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
424
	reg.s.ew_limit = ewl;
425
	reg.s.erp_limit = erp;
426
	// era, bof, erp are read-only
Martin Jeřábek's avatar
Martin Jeřábek committed
427

Martin Jeřábek's avatar
Martin Jeřábek committed
428
	priv->write_reg(priv, CTU_CAN_FD_EWL, reg.u32);
429 430
}

Martin Jeřábek's avatar
Martin Jeřábek committed
431
void ctu_can_fd_read_err_ctrs(struct ctucanfd_priv *priv, struct can_berr_counter *ctr)
432 433
{
	union ctu_can_fd_rxc_txc reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
434

Martin Jeřábek's avatar
Martin Jeřábek committed
435
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_RXC);
436 437
	ctr->txerr = reg.s.rxc_val;
	ctr->rxerr = reg.s.txc_val;
438 439
}

440
enum can_state ctu_can_fd_read_error_state(struct ctucanfd_priv *priv)
441 442
{
	union ctu_can_fd_ewl_erp_fault_state reg;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
443 444
	union ctu_can_fd_rxc_txc err;

Martin Jeřábek's avatar
Martin Jeřábek committed
445 446
	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
447

448
	if (reg.s.era){
Martin Jeřábek's avatar
Martin Jeřábek committed
449
		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
450 451 452
			return CAN_STATE_ERROR_ACTIVE;
		else
			return CAN_STATE_ERROR_WARNING;
453
	}else if (reg.s.erp)
454
		return CAN_STATE_ERROR_PASSIVE;
455
	else if (reg.s.bof)
456
		return CAN_STATE_BUS_OFF;
Martin Jeřábek's avatar
Martin Jeřábek committed
457 458
	WARN(true, "Invalid error state");
	return CAN_STATE_ERROR_PASSIVE;
459 460
}

461
void ctu_can_fd_set_err_ctrs(struct ctucanfd_priv *priv, const struct can_berr_counter *ctr)
462 463 464
{
	union ctu_can_fd_ctr_pres reg;
	reg.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
465

466 467
	reg.s.ctpv = ctr->txerr;
	reg.s.ptx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
468
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
469

470 471 472
	reg.s.ctpv = ctr->rxerr;
	reg.s.ptx = 0;
	reg.s.prx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
473
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
474 475 476
}


477
bool ctu_can_fd_get_mask_filter_support(struct ctucanfd_priv *priv, u8 fnum)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
478 479
{
	union ctu_can_fd_filter_control_filter_status reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
480
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
481

482 483 484
	switch (fnum){
	case CTU_CAN_FD_FILTER_A :
		if (reg.s.sfa) return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
485
	break;
486 487
	case CTU_CAN_FD_FILTER_B :
		if (reg.s.sfb) return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
488
	break;
489 490
	case CTU_CAN_FD_FILTER_C :
		if (reg.s.sfc) return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
491 492 493 494 495 496
	break;
	}

	return false;
}

497
bool ctu_can_fd_get_range_filter_support(struct ctucanfd_priv *priv)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
498 499
{
	union ctu_can_fd_filter_control_filter_status reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
500
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
501

502
	if (reg.s.sfr)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
503 504 505 506 507
		return true;

	return false;
}

508
bool ctu_can_fd_set_mask_filter(struct ctucanfd_priv *priv, u8 fnum, bool enable,
509
				const struct can_filter *filter)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
510 511 512
{
	union ctu_can_fd_filter_control_filter_status creg;
	enum ctu_can_fd_regs maddr,vaddr;
Martin Jeřábek's avatar
Martin Jeřábek committed
513 514
	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
515 516
	uint8_t val = 0;

517
	if (!ctu_can_fd_get_mask_filter_support(priv, fnum))
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
518 519 520 521 522
		return false;

	if (enable)
		val = 1;

Martin Jeřábek's avatar
Martin Jeřábek committed
523
	creg.u32 = priv->read_reg(priv, CTU_CAN_FD_FILTER_CONTROL);
Martin Jeřábek's avatar
Martin Jeřábek committed
524 525
	//maddr = 0;
	//vaddr = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
526 527

	switch (fnum){
528
	case CTU_CAN_FD_FILTER_A :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
529
		maddr = CTU_CAN_FD_FILTER_A_MASK;
Martin Jeřábek's avatar
Martin Jeřábek committed
530
		vaddr = CTU_CAN_FD_FILTER_A_VAL;
531 532 533
		creg.s.fanb = val;
		creg.s.fane = val;
		creg.s.fafb = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
534
		creg.s.fafe = val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
535
	break;
536
	case CTU_CAN_FD_FILTER_B :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
537 538
		maddr = CTU_CAN_FD_FILTER_B_MASK;
		vaddr = CTU_CAN_FD_FILTER_B_VAL;
539 540 541 542
		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
543
	break;
544
	case CTU_CAN_FD_FILTER_C :
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
545 546
		maddr = CTU_CAN_FD_FILTER_C_MASK;
		vaddr = CTU_CAN_FD_FILTER_C_VAL;
547 548 549 550
		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
551 552 553 554 555
	break;
	default:
		return false;
	}

Martin Jeřábek's avatar
Martin Jeřábek committed
556 557
	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
558 559 560
	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
561 562 563
	return true;
}

564
void ctu_can_fd_set_range_filter(struct ctucanfd_priv *priv, canid_t low_th,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
565 566
				 canid_t high_th, bool enable)
{
Martin Jeřábek's avatar
Martin Jeřábek committed
567
	union ctu_can_fd_identifier_w hwid_low;
568 569
	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
570

Martin Jeřábek's avatar
Martin Jeřábek committed
571 572
	hwid_low = ctu_can_fd_id_to_hwid(low_th);
	hwid_high = ctu_can_fd_id_to_hwid(high_th);
573

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

576 577 578 579 580
	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
581 582 583
	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
584
}
585

586
void ctu_can_fd_set_rx_tsop(struct ctucanfd_priv *priv, enum ctu_can_fd_rx_settings_rtsop val)
587 588 589
{
	union ctu_can_fd_rx_status_rx_settings reg;
	reg.u32 = 0;
590
	reg.s.rtsop = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
591
	priv->write_reg(priv, CTU_CAN_FD_RX_STATUS, reg.u32);
592 593
}

Martin Jeřábek's avatar
Martin Jeřábek committed
594
void ctu_can_fd_read_rx_frame(struct ctucanfd_priv *priv, struct canfd_frame *cf, u64 *ts)
595 596
{
	union ctu_can_fd_frame_form_w ffw;
Martin Jeřábek's avatar
Martin Jeřábek committed
597

Martin Jeřábek's avatar
Martin Jeřábek committed
598 599 600 601 602 603
	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)
{
604
	union ctu_can_fd_identifier_w idw;
Martin Jeřábek's avatar
Martin Jeřábek committed
605
	unsigned i;
Martin Jeřábek's avatar
Martin Jeřábek committed
606 607

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

611
	// BRS, ESI, RTR Flags
Martin Jeřábek's avatar
Martin Jeřábek committed
612
	if (ffw.s.fdf == FD_CAN) {
613
		if (ffw.s.brs == BR_SHIFT)
614
			cf->flags |= CANFD_BRS;
Martin Jeřábek's avatar
Martin Jeřábek committed
615
		if (ffw.s.esi_rsv == ESI_ERR_PASIVE)
616
			cf->flags |= CANFD_ESI;
Martin Jeřábek's avatar
Martin Jeřábek committed
617
	} else if (ffw.s.rtr == RTR_FRAME)
618
		cf->can_id |= CAN_RTR_FLAG;
Martin Jeřábek's avatar
Martin Jeřábek committed
619

620
	// DLC
Martin Jeřábek's avatar
Martin Jeřábek committed
621
	if (ffw.s.dlc <= 8) {
Martin Jeřábek's avatar
Martin Jeřábek committed
622
		cf->len = ffw.s.dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
623
	} else {
Martin Jeřábek's avatar
Martin Jeřábek committed
624
		if (ffw.s.fdf == FD_CAN)
625
			cf->len = (ffw.s.rwcnt - 3) << 2;
626 627 628 629
		else
			cf->len = 8;
	}

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

632
	// Timestamp
Martin Jeřábek's avatar
Martin Jeřábek committed
633 634
	*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
635

636
	// Data
637 638 639 640
	for (i = 0; i < cf->len; i += 4) {
		u32 data = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
		*(u32 *)(cf->data + i) = data;
	}
641 642
}

643
enum ctu_can_fd_tx_status_tx1s ctu_can_fd_get_tx_status(struct ctucanfd_priv *priv, u8 buf)
644 645
{
	union ctu_can_fd_tx_status reg;
646
	uint32_t status;
Martin Jeřábek's avatar
Martin Jeřábek committed
647 648

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

650
	switch (buf) {
651
	case CTU_CAN_FD_TXT_BUFFER_1 : status = reg.s.tx1s;
652
	break;
653
	case CTU_CAN_FD_TXT_BUFFER_2 : status = reg.s.tx2s;
654
	break;
655
	case CTU_CAN_FD_TXT_BUFFER_3 : status = reg.s.tx3s;
656
	break;
657
	case CTU_CAN_FD_TXT_BUFFER_4 : status = reg.s.tx4s;
658 659
	break;
	default :
660
		status = ~0;
661
	}
662
	return (enum ctu_can_fd_tx_status_tx1s) status;
663 664
}

665
bool ctu_can_fd_is_txt_buf_accessible(struct ctucanfd_priv *priv, u8 buf)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
666 667 668
{
	enum ctu_can_fd_tx_status_tx1s buf_status;

669
	buf_status = ctu_can_fd_get_tx_status(priv, buf);
Martin Jeřábek's avatar
Martin Jeřábek committed
670
	if (buf_status == TXT_RDY || buf_status == TXT_TRAN
Martin Jeřábek's avatar
Martin Jeřábek committed
671
		|| buf_status == TXT_ABTP)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
672 673 674 675 676
 		return false;

	return true;
}

677
bool ctu_can_fd_txt_buf_give_command(struct ctucanfd_priv *priv, u8 cmd, u8 buf)
678 679 680
{
	union ctu_can_fd_tx_command reg;
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
681

Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
682
	switch (buf){
Martin Jeřábek's avatar
Martin Jeřábek committed
683
	case CTU_CAN_FD_TXT_BUFFER_1: reg.s.txb1 = 1;
684
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
685
	case CTU_CAN_FD_TXT_BUFFER_2: reg.s.txb2 = 1;
686
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
687
	case CTU_CAN_FD_TXT_BUFFER_3: reg.s.txb3 = 1;
688
	break;
Martin Jeřábek's avatar
Martin Jeřábek committed
689
	case CTU_CAN_FD_TXT_BUFFER_4: reg.s.txb4 = 1;
690
	break;
691
	default:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
692 693
		return false;
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
694

Martin Jeřábek's avatar
Martin Jeřábek committed
695
	// TODO: use named constants for the command
696
	if (cmd & 0x1) {
697
		reg.s.txce = 1;
698
	} else if (cmd & 0x2) {
699
		reg.s.txcr = 1;
700
	} else if (cmd & 0x4) {
701
		reg.s.txca = 1;
702
	} else {
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
703
		return false;
704
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
705

Martin Jeřábek's avatar
Martin Jeřábek committed
706
	priv->write_reg(priv, CTU_CAN_FD_TX_COMMAND, reg.u32);
Martin Jeřábek's avatar
Martin Jeřábek committed
707
	return true;
708 709
}

710
void ctu_can_fd_set_txt_priority(struct ctucanfd_priv *priv, const u8 *prio)
711 712 713
{
	union ctu_can_fd_tx_priority reg;
	reg.u32 = 0;
714 715 716 717
	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
718

Martin Jeřábek's avatar
Martin Jeřábek committed
719
	priv->write_reg(priv, CTU_CAN_FD_TX_PRIORITY, reg.u32);
720 721
}

Martin Jeřábek's avatar
Martin Jeřábek committed
722 723 724 725 726 727 728
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)
729
{
Martin Jeřábek's avatar
Martin Jeřábek committed
730
	enum ctu_can_fd_regs buf_base;
731 732
	union ctu_can_fd_frame_form_w ffw;
	union ctu_can_fd_identifier_w idw;
733
	u8 dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
734
	unsigned i;
Martin Jeřábek's avatar
Martin Jeřábek committed
735

736 737
	ffw.u32 = 0;
	idw.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
738 739

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

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

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