ctu_can_fd_hw.c 18.9 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.
28
 ******************************************************************************/
29

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

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

40
void ctucan_hw_write32(struct ctucan_hw_priv *priv,
41
			enum ctu_can_fd_can_registers reg, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
42 43 44 45
{
	iowrite32(val, (char *)priv->mem_base + reg);
}

46
void ctucan_hw_write32_be(struct ctucan_hw_priv *priv,
47
			   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
u32 ctucan_hw_read32(struct ctucan_hw_priv *priv,
53
		      enum ctu_can_fd_can_registers reg)
Martin Jeřábek's avatar
Martin Jeřábek committed
54
{
55
	return ioread32((char *)priv->mem_base + reg);
Martin Jeřábek's avatar
Martin Jeřábek committed
56 57
}

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

64
static void ctucan_hw_write_txt_buf(struct ctucan_hw_priv *priv,
65 66
				     enum ctu_can_fd_can_registers buf_base,
				     u32 offset, u32 val)
Martin Jeřábek's avatar
Martin Jeřábek committed
67 68 69 70
{
	priv->write_reg(priv, buf_base + offset, val);
}

71
static inline union ctu_can_fd_identifier_w ctucan_hw_id_to_hwid(canid_t id)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
72
{
Martin Jeřábek's avatar
Martin Jeřábek committed
73
	union ctu_can_fd_identifier_w hwid;
74

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

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

80
		/* getting lowest 18 bits, replace with sth nicer... */
Martin Jeřábek's avatar
Martin Jeřábek committed
81
		hwid.s.identifier_ext = (id & 0x3FFFF);
82
	} else {
Martin Jeřábek's avatar
Martin Jeřábek committed
83
		hwid.s.identifier_base = id & CAN_SFF_MASK;
84
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
85
	return hwid;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
86
}
Martin Jeřábek's avatar
Martin Jeřábek committed
87 88

// TODO: rename or do not depend on previous value of id
89
static inline void ctucan_hw_hwid_to_id(union ctu_can_fd_identifier_w hwid,
90
					 canid_t *id,
Martin Jeřábek's avatar
Martin Jeřábek committed
91
					 enum ctu_can_fd_frame_form_w_ide type)
Martin Jeřábek's avatar
Martin Jeřábek committed
92
{
93
	/* Preserve flags which we dont set */
94
	*id &= ~(CAN_EFF_FLAG | CAN_EFF_MASK);
Martin Jeřábek's avatar
Martin Jeřábek committed
95

96
	if (type == EXTENDED) {
97 98 99
		*id |= CAN_EFF_FLAG;
		*id |= hwid.s.identifier_base << 18;
		*id |= hwid.s.identifier_ext;
100
	} else {
101
		*id = hwid.s.identifier_base;
102
	}
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
103 104
}

105
static bool ctucan_hw_len_to_dlc(u8 len, u8 *dlc)
106
{
107 108
	*dlc = can_len2dlc(len);
	return true;
109 110
}

111
bool ctucan_hw_check_access(struct ctucan_hw_priv *priv)
112 113
{
	union ctu_can_fd_device_id_version reg;
114

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

117 118
	if (reg.s.device_id != CTU_CAN_FD_ID)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
119

120
	return true;
121 122
}

123
u32 ctucan_hw_get_version(struct ctucan_hw_priv *priv)
124 125
{
	union ctu_can_fd_device_id_version reg;
126

Martin Jeřábek's avatar
Martin Jeřábek committed
127
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
128
	return reg.s.ver_major * 10 + reg.s.ver_minor;
129 130
}

131
void ctucan_hw_enable(struct ctucan_hw_priv *priv, bool enable)
132
{
133
	union ctu_can_fd_mode_settings reg;
134

Martin Jeřábek's avatar
Martin Jeřábek committed
135
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
136
	reg.s.ena = enable ? CTU_CAN_ENABLED : CTU_CAN_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
137 138 139
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
}

140
void ctucan_hw_reset(struct ctucan_hw_priv *priv)
Martin Jeřábek's avatar
Martin Jeřábek committed
141
{
142
	union ctu_can_fd_mode_settings mode;
143

144
	mode.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
145
	mode.s.rst = 1;
146 147 148
	/* it does not matter that we overwrite the rest of the reg
	 * - we're resetting
	 */
Martin Jeřábek's avatar
Martin Jeřábek committed
149
	priv->write_reg(priv, CTU_CAN_FD_MODE, mode.u32);
150 151
}

152
bool ctucan_hw_set_ret_limit(struct ctucan_hw_priv *priv, bool enable, u8 limit)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
153
{
154
	union ctu_can_fd_mode_settings reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
155

156 157
	if (limit > CTU_CAN_FD_RETR_MAX)
		return false;
Martin Jeřábek's avatar
Martin Jeřábek committed
158

Martin Jeřábek's avatar
Martin Jeřábek committed
159
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_MODE);
160
	reg.s.rtrle = enable ? RTRLE_ENABLED : RTRLE_DISABLED;
Martin Jeřábek's avatar
Martin Jeřábek committed
161
	reg.s.rtrth = limit & 0xF;
Martin Jeřábek's avatar
Martin Jeřábek committed
162
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
163
	return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
164 165
}

166
void ctucan_hw_set_mode_reg(struct ctucan_hw_priv *priv,
167
			     const struct can_ctrlmode *mode)
168
{
Martin Jeřábek's avatar
Martin Jeřábek committed
169
	u32 flags = mode->flags;
170
	union ctu_can_fd_mode_settings reg;
171

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

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

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

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

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

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

Martin Jeřábek's avatar
Martin Jeřábek committed
194
	priv->write_reg(priv, CTU_CAN_FD_MODE, reg.u32);
195 196
}

197
void ctucan_hw_rel_rx_buf(struct ctucan_hw_priv *priv)
198
{
199
	union ctu_can_fd_command reg;
200

201
	reg.u32 = 0;
202
	reg.s.rrb = 1;
203
	priv->write_reg(priv, CTU_CAN_FD_COMMAND, reg.u32);
204 205
}

206
void ctucan_hw_clr_overrun_flag(struct ctucan_hw_priv *priv)
207
{
208
	union ctu_can_fd_command reg;
209

210
	reg.u32 = 0;
211
	reg.s.cdo = 1;
212
	priv->write_reg(priv, CTU_CAN_FD_COMMAND, reg.u32);
213 214
}

215
static void ctucan_hw_int_conf(struct ctucan_hw_priv *priv,
216
				enum ctu_can_fd_can_registers sreg,
217
				enum ctu_can_fd_can_registers creg,
218 219
				union ctu_can_fd_int_stat mask,
				union ctu_can_fd_int_stat val)
220
{
Martin Jeřábek's avatar
Martin Jeřábek committed
221 222
	priv->write_reg(priv, sreg, mask.u32 & val.u32);
	priv->write_reg(priv, creg, mask.u32 & (~val.u32));
223 224
}

225
void ctucan_hw_int_ena(struct ctucan_hw_priv *priv,
226
			union ctu_can_fd_int_stat mask,
227
			union ctu_can_fd_int_stat val)
228
{
229
	ctucan_hw_int_conf(priv, CTU_CAN_FD_INT_ENA_SET,
230
			    CTU_CAN_FD_INT_ENA_CLR, mask, val);
231 232
}

233
void ctucan_hw_int_mask(struct ctucan_hw_priv *priv,
234
			 union ctu_can_fd_int_stat mask,
235
			 union ctu_can_fd_int_stat val)
236
{
237
	ctucan_hw_int_conf(priv, CTU_CAN_FD_INT_MASK_SET,
238
			    CTU_CAN_FD_INT_MASK_CLR, mask, val);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
239 240
}

241
void ctucan_hw_set_mode(struct ctucan_hw_priv *priv,
242
			 const struct can_ctrlmode *mode)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
243
{
244
	ctucan_hw_set_mode_reg(priv, mode);
Martin Jeřábek's avatar
Martin Jeřábek committed
245

246
	/* One shot mode supported indirectly via Retransmitt limit */
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
247
	if (mode->mask & CAN_CTRLMODE_ONE_SHOT)
248
		ctucan_hw_set_ret_limit(priv, !!(mode->flags &
249
					 CAN_CTRLMODE_ONE_SHOT), 0);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
250

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

255 256
		ena.u32 = 0;
		mask.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
257 258
		ena.s.bei = !!(mode->flags & CAN_CTRLMODE_ONE_SHOT);
		mask.s.bei = 1;
259
		ctucan_hw_int_ena(priv, ena, mask);
Martin Jeřábek's avatar
Martin Jeřábek committed
260
	}
261 262
}

263
const struct can_bittiming_const ctu_can_fd_bit_timing_max = {
264
	.name = "ctu_can_fd",
265 266 267 268 269 270
	.tseg1_min = 2,
	.tseg1_max = 190,
	.tseg2_min = 1,
	.tseg2_max = 63,
	.sjw_max = 31,
	.brp_min = 1,
271
	.brp_max = 8,
272 273 274
	.brp_inc = 1,
};

275
const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = {
276
	.name = "ctu_can_fd",
277 278 279 280 281 282
	.tseg1_min = 2,
	.tseg1_max = 94,
	.tseg2_min = 1,
	.tseg2_max = 31,
	.sjw_max = 31,
	.brp_min = 1,
283
	.brp_max = 2,
284 285 286
	.brp_inc = 1,
};

287
void ctucan_hw_set_nom_bittiming(struct ctucan_hw_priv *priv,
288
				  struct can_bittiming *nbt)
289 290
{
	union ctu_can_fd_btr btr;
291

292
	/* The timing calculation functions have only constraints on tseg1,
293
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
294 295
	 * 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.
296 297 298
	 */
	u32 prop_seg = nbt->prop_seg;
	u32 phase_seg1 = nbt->phase_seg1;
299

300 301 302 303 304 305 306 307
	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;
308 309
	btr.s.prop = prop_seg;
	btr.s.ph1 = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
310 311 312
	btr.s.ph2 = nbt->phase_seg2;
	btr.s.brp = nbt->brp;
	btr.s.sjw = nbt->sjw;
313

Martin Jeřábek's avatar
Martin Jeřábek committed
314
	priv->write_reg(priv, CTU_CAN_FD_BTR, btr.u32);
315 316
}

317
void ctucan_hw_set_data_bittiming(struct ctucan_hw_priv *priv,
318
				   struct can_bittiming *dbt)
319 320
{
	union ctu_can_fd_btr_fd btr_fd;
321

322
	/* The timing calculation functions have only constraints on tseg1,
323
	 * which is prop_seg + phase1_seg combined. tseg1 is then split in half
324 325 326
	 * 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.
327 328 329
	 */
	u32 prop_seg = dbt->prop_seg;
	u32 phase_seg1 = dbt->phase_seg1;
330

331 332 333 334 335 336
	if (phase_seg1 > 31) {
		prop_seg += phase_seg1 - 31;
		phase_seg1 = 31;
		dbt->prop_seg = prop_seg;
		dbt->phase_seg1 = phase_seg1;
	}
337

338
	btr_fd.u32 = 0;
339 340
	btr_fd.s.prop_fd = prop_seg;
	btr_fd.s.ph1_fd = phase_seg1;
Martin Jeřábek's avatar
Martin Jeřábek committed
341 342 343
	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
344

Martin Jeřábek's avatar
Martin Jeřábek committed
345
	priv->write_reg(priv, CTU_CAN_FD_BTR_FD, btr_fd.u32);
346 347
}

348
void ctucan_hw_set_err_limits(struct ctucan_hw_priv *priv, u8 ewl, u8 erp)
349 350
{
	union ctu_can_fd_ewl_erp_fault_state reg;
351

352
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
353
	reg.s.ew_limit = ewl;
354
	reg.s.erp_limit = erp;
355
	// era, bof, erp are read-only
Martin Jeřábek's avatar
Martin Jeřábek committed
356

Martin Jeřábek's avatar
Martin Jeřábek committed
357
	priv->write_reg(priv, CTU_CAN_FD_EWL, reg.u32);
358 359
}

360
void ctucan_hw_read_err_ctrs(struct ctucan_hw_priv *priv,
361
			      struct can_berr_counter *ctr)
362
{
363
	union ctu_can_fd_rec_tec reg;
Martin Jeřábek's avatar
Martin Jeřábek committed
364

365
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_REC);
366 367
	ctr->txerr = reg.s.tec_val;
	ctr->rxerr = reg.s.rec_val;
368 369
}

370
enum can_state ctucan_hw_read_error_state(struct ctucan_hw_priv *priv)
371 372
{
	union ctu_can_fd_ewl_erp_fault_state reg;
373
	union ctu_can_fd_rec_tec err;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
374

Martin Jeřábek's avatar
Martin Jeřábek committed
375
	reg.u32 = priv->read_reg(priv, CTU_CAN_FD_EWL);
376
	err.u32 = priv->read_reg(priv, CTU_CAN_FD_REC);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
377

378
	if (reg.s.era) {
379 380
		if (reg.s.ew_limit > err.s.rec_val &&
		    reg.s.ew_limit > err.s.tec_val)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
381 382 383
			return CAN_STATE_ERROR_ACTIVE;
		else
			return CAN_STATE_ERROR_WARNING;
384
	} else if (reg.s.erp) {
385
		return CAN_STATE_ERROR_PASSIVE;
386
	} else if (reg.s.bof) {
387
		return CAN_STATE_BUS_OFF;
388
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
389 390
	WARN(true, "Invalid error state");
	return CAN_STATE_ERROR_PASSIVE;
391 392
}

393
void ctucan_hw_set_err_ctrs(struct ctucan_hw_priv *priv,
394
			     const struct can_berr_counter *ctr)
395 396
{
	union ctu_can_fd_ctr_pres reg;
397

398
	reg.u32 = 0;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
399

400 401
	reg.s.ctpv = ctr->txerr;
	reg.s.ptx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
402
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
403

404 405 406
	reg.s.ctpv = ctr->rxerr;
	reg.s.ptx = 0;
	reg.s.prx = 1;
Martin Jeřábek's avatar
Martin Jeřábek committed
407
	priv->write_reg(priv, CTU_CAN_FD_CTR_PRES, reg.u32);
408 409
}

410
bool ctucan_hw_get_mask_filter_support(struct ctucan_hw_priv *priv, u8 fnum)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
411 412
{
	union ctu_can_fd_filter_control_filter_status reg;
413

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

416 417 418 419
	switch (fnum) {
	case CTU_CAN_FD_FILTER_A:
		if (reg.s.sfa)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
420
	break;
421 422 423
	case CTU_CAN_FD_FILTER_B:
		if (reg.s.sfb)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
424
	break;
425 426 427
	case CTU_CAN_FD_FILTER_C:
		if (reg.s.sfc)
			return true;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
428 429 430 431 432 433
	break;
	}

	return false;
}

434
bool ctucan_hw_get_range_filter_support(struct ctucan_hw_priv *priv)
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
	if (reg.s.sfr)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
441 442 443 444 445
		return true;

	return false;
}

446
bool ctucan_hw_set_mask_filter(struct ctucan_hw_priv *priv, u8 fnum,
447
				bool enable, const struct can_filter *filter)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
448 449
{
	union ctu_can_fd_filter_control_filter_status creg;
450
	enum ctu_can_fd_can_registers maddr, vaddr;
Martin Jeřábek's avatar
Martin Jeřábek committed
451 452
	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
453 454
	uint8_t val = 0;

455
	if (!ctucan_hw_get_mask_filter_support(priv, fnum))
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
456 457 458 459 460
		return false;

	if (enable)
		val = 1;

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

463 464
	switch (fnum) {
	case CTU_CAN_FD_FILTER_A:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
465
		maddr = CTU_CAN_FD_FILTER_A_MASK;
Martin Jeřábek's avatar
Martin Jeřábek committed
466
		vaddr = CTU_CAN_FD_FILTER_A_VAL;
467 468 469
		creg.s.fanb = val;
		creg.s.fane = val;
		creg.s.fafb = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
470
		creg.s.fafe = val;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
471
	break;
472
	case CTU_CAN_FD_FILTER_B:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
473 474
		maddr = CTU_CAN_FD_FILTER_B_MASK;
		vaddr = CTU_CAN_FD_FILTER_B_VAL;
475 476 477 478
		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
479
	break;
480
	case CTU_CAN_FD_FILTER_C:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
481 482
		maddr = CTU_CAN_FD_FILTER_C_MASK;
		vaddr = CTU_CAN_FD_FILTER_C_VAL;
483 484 485 486
		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
487 488 489 490 491
	break;
	default:
		return false;
	}

492 493
	hwid_mask = ctucan_hw_id_to_hwid(filter->can_id);
	hwid_val = ctucan_hw_id_to_hwid(filter->can_mask);
Martin Jeřábek's avatar
Martin Jeřábek committed
494 495 496
	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
497 498 499
	return true;
}

500
void ctucan_hw_set_range_filter(struct ctucan_hw_priv *priv, canid_t low_th,
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
501 502
				 canid_t high_th, bool enable)
{
Martin Jeřábek's avatar
Martin Jeřábek committed
503
	union ctu_can_fd_identifier_w hwid_low;
504 505
	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
506

507 508
	hwid_low = ctucan_hw_id_to_hwid(low_th);
	hwid_high = ctucan_hw_id_to_hwid(high_th);
509

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

512 513 514 515 516
	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
517 518 519
	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
520
}
521

522
void ctucan_hw_set_rx_tsop(struct ctucan_hw_priv *priv,
523
			    enum ctu_can_fd_rx_settings_rtsop val)
524 525
{
	union ctu_can_fd_rx_status_rx_settings reg;
526

527
	reg.u32 = 0;
528
	reg.s.rtsop = val;
Martin Jeřábek's avatar
Martin Jeřábek committed
529
	priv->write_reg(priv, CTU_CAN_FD_RX_STATUS, reg.u32);
530 531
}

532
void ctucan_hw_read_rx_frame(struct ctucan_hw_priv *priv,
533
			      struct canfd_frame *cf, u64 *ts)
534 535
{
	union ctu_can_fd_frame_form_w ffw;
Martin Jeřábek's avatar
Martin Jeřábek committed
536

Martin Jeřábek's avatar
Martin Jeřábek committed
537
	ffw.u32 = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
538
	ctucan_hw_read_rx_frame_ffw(priv, cf, ts, ffw);
Martin Jeřábek's avatar
Martin Jeřábek committed
539 540
}

541
void ctucan_hw_read_rx_frame_ffw(struct ctucan_hw_priv *priv,
542 543
				  struct canfd_frame *cf, u64 *ts,
				  union ctu_can_fd_frame_form_w ffw)
Martin Jeřábek's avatar
Martin Jeřábek committed
544
{
545
	union ctu_can_fd_identifier_w idw;
546 547
	unsigned int i;
	enum ctu_can_fd_frame_form_w_ide ide;
Martin Jeřábek's avatar
Martin Jeřábek committed
548 549

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

553
	/* BRS, ESI, RTR Flags */
Martin Jeřábek's avatar
Martin Jeřábek committed
554
	if (ffw.s.fdf == FD_CAN) {
555
		if (ffw.s.brs == BR_SHIFT)
556
			cf->flags |= CANFD_BRS;
Martin Jeřábek's avatar
Martin Jeřábek committed
557
		if (ffw.s.esi_rsv == ESI_ERR_PASIVE)
558
			cf->flags |= CANFD_ESI;
559
	} else if (ffw.s.rtr == RTR_FRAME) {
560
		cf->can_id |= CAN_RTR_FLAG;
561
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
562

563
	/* DLC */
Martin Jeřábek's avatar
Martin Jeřábek committed
564
	if (ffw.s.dlc <= 8) {
Martin Jeřábek's avatar
Martin Jeřábek committed
565
		cf->len = ffw.s.dlc;
Martin Jeřábek's avatar
Martin Jeřábek committed
566
	} else {
Martin Jeřábek's avatar
Martin Jeřábek committed
567
		if (ffw.s.fdf == FD_CAN)
568
			cf->len = (ffw.s.rwcnt - 3) << 2;
569 570 571 572
		else
			cf->len = 8;
	}

573
	ide = (enum ctu_can_fd_frame_form_w_ide)ffw.s.ide;
574
	ctucan_hw_hwid_to_id(idw, &cf->can_id, ide);
Martin Jeřábek's avatar
Martin Jeřábek committed
575

576
	/* Timestamp */
Martin Jeřábek's avatar
Martin Jeřábek committed
577 578
	*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
579

580
	/* Data */
581 582 583 584
	for (i = 0; i < cf->len; i += 4) {
		u32 data = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
		*(u32 *)(cf->data + i) = data;
	}
585 586
}

587
enum ctu_can_fd_tx_status_tx1s ctucan_hw_get_tx_status(struct ctucan_hw_priv
588
							*priv, u8 buf)
589 590
{
	union ctu_can_fd_tx_status reg;
591
	uint32_t status;
Martin Jeřábek's avatar
Martin Jeřábek committed
592 593

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

595
	switch (buf) {
596 597 598 599 600 601 602 603 604 605 606 607 608
	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:
609
		status = ~0;
610
	}
611
	return (enum ctu_can_fd_tx_status_tx1s)status;
612 613
}

614
bool ctucan_hw_is_txt_buf_accessible(struct ctucan_hw_priv *priv, u8 buf)
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
615 616 617
{
	enum ctu_can_fd_tx_status_tx1s buf_status;

618
	buf_status = ctucan_hw_get_tx_status(priv, buf);
619 620
	if (buf_status == TXT_RDY || buf_status == TXT_TRAN ||
	    buf_status == TXT_ABTP)
621
		return false;
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
622 623 624 625

	return true;
}

626
bool ctucan_hw_txt_buf_give_command(struct ctucan_hw_priv *priv, u8 cmd, u8 buf)
627 628
{
	union ctu_can_fd_tx_command reg;
629

630
	reg.u32 = 0;
Martin Jeřábek's avatar
Martin Jeřábek committed
631

632 633 634 635 636 637 638 639 640 641 642 643 644
	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;
645
	default:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
646 647
		return false;
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
648

Martin Jeřábek's avatar
Martin Jeřábek committed
649
	// TODO: use named constants for the command
650
	if (cmd & 0x1) {
651
		reg.s.txce = 1;
652
	} else if (cmd & 0x2) {
653
		reg.s.txcr = 1;
654
	} else if (cmd & 0x4) {
655
		reg.s.txca = 1;
656
	} else {
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
657
		return false;
658
	}
Martin Jeřábek's avatar
Martin Jeřábek committed
659

Martin Jeřábek's avatar