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