1 /*
2  * Copyright (c) 2022 Henrik Brix Andersen <henrik@brixandersen.dk>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT kvaser_pcican
8 
9 #include <zephyr/drivers/can/can_sja1000.h>
10 
11 #include <zephyr/drivers/can.h>
12 #include <zephyr/drivers/pcie/pcie.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/sys/util.h>
15 
16 LOG_MODULE_REGISTER(can_kvaser_pci, CONFIG_CAN_LOG_LEVEL);
17 
18 /* AMCC S5920 I/O BAR registers */
19 #define S5920_INTCSR_REG       0x38
20 #define S5920_INTCSR_ADDINT_EN BIT(13)
21 #define S5920_PTCR_REG	       0x60
22 
23 /* Xilinx I/O BAR registers */
24 #define XLNX_VERINT_REG		0x07
25 #define XLNX_VERINT_VERSION_POS 4U
26 
27 struct can_kvaser_pci_config {
28 	void (*irq_config_func)(const struct device *dev);
29 	struct pcie_dev *pcie;
30 };
31 
32 struct can_kvaser_pci_data {
33 	io_port_t sja1000_base;
34 };
35 
can_kvaser_pci_read_reg(const struct device * dev,uint8_t reg)36 static uint8_t can_kvaser_pci_read_reg(const struct device *dev, uint8_t reg)
37 {
38 	struct can_sja1000_data *sja1000_data = dev->data;
39 	struct can_kvaser_pci_data *kvaser_data = sja1000_data->custom;
40 	io_port_t addr = kvaser_data->sja1000_base + reg;
41 
42 	return sys_in8(addr);
43 }
44 
can_kvaser_pci_write_reg(const struct device * dev,uint8_t reg,uint8_t val)45 static void can_kvaser_pci_write_reg(const struct device *dev, uint8_t reg, uint8_t val)
46 {
47 	struct can_sja1000_data *sja1000_data = dev->data;
48 	struct can_kvaser_pci_data *kvaser_data = sja1000_data->custom;
49 	io_port_t addr = kvaser_data->sja1000_base + reg;
50 
51 	sys_out8(val, addr);
52 }
53 
can_kvaser_pci_get_core_clock(const struct device * dev,uint32_t * rate)54 static int can_kvaser_pci_get_core_clock(const struct device *dev, uint32_t *rate)
55 {
56 	ARG_UNUSED(dev);
57 
58 	/* The internal clock operates at half of the oscillator frequency */
59 	*rate = MHZ(16) / 2;
60 
61 	return 0;
62 }
63 
can_kvaser_pci_init(const struct device * dev)64 static int can_kvaser_pci_init(const struct device *dev)
65 {
66 	const struct can_sja1000_config *sja1000_config = dev->config;
67 	const struct can_kvaser_pci_config *kvaser_config = sja1000_config->custom;
68 	struct can_sja1000_data *sja1000_data = dev->data;
69 	struct can_kvaser_pci_data *kvaser_data = sja1000_data->custom;
70 	struct pcie_bar iobar;
71 	static io_port_t amcc_base;
72 	static io_port_t xlnx_base;
73 	uint32_t intcsr;
74 	int err;
75 
76 	if (kvaser_config->pcie->bdf == PCIE_BDF_NONE) {
77 		LOG_ERR("failed to find PCIe device");
78 		return -ENODEV;
79 	}
80 
81 	pcie_set_cmd(kvaser_config->pcie->bdf, PCIE_CONF_CMDSTAT_IO, true);
82 
83 	/* AMCC S5920 registers */
84 	if (!pcie_probe_iobar(kvaser_config->pcie->bdf, 0, &iobar)) {
85 		LOG_ERR("failed to probe AMCC S5920 I/O BAR");
86 		return -ENODEV;
87 	}
88 
89 	amcc_base = iobar.phys_addr;
90 
91 	/* SJA1000 registers */
92 	if (!pcie_probe_iobar(kvaser_config->pcie->bdf, 1, &iobar)) {
93 		LOG_ERR("failed to probe SJA1000 I/O BAR");
94 		return -ENODEV;
95 	}
96 
97 	kvaser_data->sja1000_base = iobar.phys_addr;
98 
99 	/* Xilinx registers */
100 	if (!pcie_probe_iobar(kvaser_config->pcie->bdf, 2, &iobar)) {
101 		LOG_ERR("failed to probe Xilinx I/O BAR");
102 		return -ENODEV;
103 	}
104 
105 	xlnx_base = iobar.phys_addr;
106 	LOG_DBG("Xilinx version: %d",
107 		sys_in8(xlnx_base + XLNX_VERINT_REG) >> XLNX_VERINT_VERSION_POS);
108 
109 	/*
110 	 * Initialization sequence as per Kvaser PCIcan Hardware Reference Manual (UG 98048
111 	 * v3.0.0).
112 	 */
113 
114 	/* AMCC S5920 PCI Pass-Thru Configuration Register (PTCR) */
115 	sys_out32(0x80808080UL, amcc_base + S5920_PTCR_REG);
116 
117 	/* AMCC S5920 PCI Interrupt Control/Status Register (INTCSR) */
118 	intcsr = sys_in32(amcc_base + S5920_INTCSR_REG);
119 	intcsr |= S5920_INTCSR_ADDINT_EN;
120 	sys_out32(intcsr, amcc_base + S5920_INTCSR_REG);
121 
122 	err = can_sja1000_init(dev);
123 	if (err != 0) {
124 		LOG_ERR("failed to initialize controller (err %d)", err);
125 		return err;
126 	}
127 
128 	kvaser_config->irq_config_func(dev);
129 
130 	return 0;
131 }
132 
133 const struct can_driver_api can_kvaser_pci_driver_api = {
134 	.get_capabilities = can_sja1000_get_capabilities,
135 	.start = can_sja1000_start,
136 	.stop = can_sja1000_stop,
137 	.set_mode = can_sja1000_set_mode,
138 	.set_timing = can_sja1000_set_timing,
139 	.send = can_sja1000_send,
140 	.add_rx_filter = can_sja1000_add_rx_filter,
141 	.remove_rx_filter = can_sja1000_remove_rx_filter,
142 	.get_state = can_sja1000_get_state,
143 	.set_state_change_callback = can_sja1000_set_state_change_callback,
144 	.get_core_clock = can_kvaser_pci_get_core_clock,
145 	.get_max_filters = can_sja1000_get_max_filters,
146 #ifdef CONFIG_CAN_MANUAL_RECOVERY_MODE
147 	.recover = can_sja1000_recover,
148 #endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE */
149 	.timing_min = CAN_SJA1000_TIMING_MIN_INITIALIZER,
150 	.timing_max = CAN_SJA1000_TIMING_MAX_INITIALIZER,
151 };
152 
153 #define CAN_KVASER_PCI_OCR                                                                         \
154 	(CAN_SJA1000_OCR_OCMODE_NORMAL | CAN_SJA1000_OCR_OCTN0 | CAN_SJA1000_OCR_OCTP0 |           \
155 	 CAN_SJA1000_OCR_OCTN1 | CAN_SJA1000_OCR_OCTP1)
156 
157 #define CAN_KVASER_PCI_CDR (CAN_SJA1000_CDR_CD_DIV2 | CAN_SJA1000_CDR_CLOCK_OFF)
158 
159 #define CAN_KVASER_PCI_INIT(inst)                                                                  \
160 	static void can_kvaser_pci_config_func_##inst(const struct device *dev);                   \
161 	DEVICE_PCIE_INST_DECLARE(inst);                                                            \
162                                                                                                    \
163 	static const struct can_kvaser_pci_config can_kvaser_pci_config_##inst = {                 \
164 		DEVICE_PCIE_INST_INIT(inst, pcie),                                                 \
165 		.irq_config_func = can_kvaser_pci_config_func_##inst                               \
166 	};                                                                                         \
167                                                                                                    \
168 	static const struct can_sja1000_config can_sja1000_config_##inst =                         \
169 		CAN_SJA1000_DT_CONFIG_INST_GET(inst, &can_kvaser_pci_config_##inst,                \
170 					       can_kvaser_pci_read_reg, can_kvaser_pci_write_reg,  \
171 					       CAN_KVASER_PCI_OCR, CAN_KVASER_PCI_CDR, 0);         \
172                                                                                                    \
173 	static struct can_kvaser_pci_data can_kvaser_pci_data_##inst;                              \
174                                                                                                    \
175 	static struct can_sja1000_data can_sja1000_data_##inst =                                   \
176 		CAN_SJA1000_DATA_INITIALIZER(&can_kvaser_pci_data_##inst);                         \
177                                                                                                    \
178 	CAN_DEVICE_DT_INST_DEFINE(inst, can_kvaser_pci_init, NULL, &can_sja1000_data_##inst,       \
179 				  &can_sja1000_config_##inst, POST_KERNEL,                         \
180 				  CONFIG_CAN_INIT_PRIORITY, &can_kvaser_pci_driver_api);           \
181                                                                                                    \
182 	static void can_kvaser_pci_config_func_##inst(const struct device *dev)                    \
183 	{                                                                                          \
184 		IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), can_sja1000_isr,      \
185 			    DEVICE_DT_INST_GET(inst), DT_INST_IRQ(inst, sense));                   \
186 		irq_enable(DT_INST_IRQN(inst));                                                    \
187 	}
188 
189 DT_INST_FOREACH_STATUS_OKAY(CAN_KVASER_PCI_INIT)
190